user.go 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429
  1. package controller
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "github.com/pquerna/otp"
  9. "image/png"
  10. "net/http"
  11. "reflect"
  12. "time"
  13. "github.com/google/uuid"
  14. "github.com/gorilla/mux"
  15. "github.com/gorilla/websocket"
  16. "github.com/gravitl/netmaker/auth"
  17. "github.com/gravitl/netmaker/logger"
  18. "github.com/gravitl/netmaker/logic"
  19. "github.com/gravitl/netmaker/models"
  20. "github.com/gravitl/netmaker/mq"
  21. "github.com/gravitl/netmaker/schema"
  22. "github.com/gravitl/netmaker/servercfg"
  23. "github.com/pquerna/otp/totp"
  24. "golang.org/x/exp/slog"
  25. )
  26. var (
  27. upgrader = websocket.Upgrader{}
  28. )
  29. var ListRoles = listRoles
  30. func userHandlers(r *mux.Router) {
  31. r.HandleFunc("/api/users/adm/hassuperadmin", hasSuperAdmin).Methods(http.MethodGet)
  32. r.HandleFunc("/api/users/adm/createsuperadmin", createSuperAdmin).Methods(http.MethodPost)
  33. r.HandleFunc("/api/users/adm/transfersuperadmin/{username}", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).
  34. Methods(http.MethodPost)
  35. r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost)
  36. r.HandleFunc("/api/users/{username}/auth/init-totp", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(initiateTOTPSetup)))).Methods(http.MethodPost)
  37. r.HandleFunc("/api/users/{username}/auth/complete-totp", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(completeTOTPSetup)))).Methods(http.MethodPost)
  38. r.HandleFunc("/api/users/{username}/auth/verify-totp", logic.PreAuthCheck(logic.ContinueIfUserMatch(http.HandlerFunc(verifyTOTP)))).Methods(http.MethodPost)
  39. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUser))).Methods(http.MethodPut)
  40. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).Methods(http.MethodPost)
  41. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete)
  42. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)
  43. r.HandleFunc("/api/users/{username}/enable", logic.SecurityCheck(true, http.HandlerFunc(enableUserAccount))).Methods(http.MethodPost)
  44. r.HandleFunc("/api/users/{username}/disable", logic.SecurityCheck(true, http.HandlerFunc(disableUserAccount))).Methods(http.MethodPost)
  45. r.HandleFunc("/api/users/{username}/settings", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserSettings)))).Methods(http.MethodGet)
  46. r.HandleFunc("/api/users/{username}/settings", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(updateUserSettings)))).Methods(http.MethodPut)
  47. r.HandleFunc("/api/v1/users", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserV1)))).Methods(http.MethodGet)
  48. r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet)
  49. r.HandleFunc("/api/v1/users/roles", logic.SecurityCheck(true, http.HandlerFunc(ListRoles))).Methods(http.MethodGet)
  50. r.HandleFunc("/api/v1/users/access_token", logic.SecurityCheck(true, http.HandlerFunc(createUserAccessToken))).Methods(http.MethodPost)
  51. r.HandleFunc("/api/v1/users/access_token", logic.SecurityCheck(true, http.HandlerFunc(getUserAccessTokens))).Methods(http.MethodGet)
  52. r.HandleFunc("/api/v1/users/access_token", logic.SecurityCheck(true, http.HandlerFunc(deleteUserAccessTokens))).Methods(http.MethodDelete)
  53. r.HandleFunc("/api/v1/users/logout", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(logout)))).Methods(http.MethodPost)
  54. }
  55. // @Summary Authenticate a user to retrieve an authorization token
  56. // @Router /api/v1/users/{username}/access_token [post]
  57. // @Tags Auth
  58. // @Accept json
  59. // @Param body body models.UserAuthParams true "Authentication parameters"
  60. // @Success 200 {object} models.SuccessResponse
  61. // @Failure 400 {object} models.ErrorResponse
  62. // @Failure 401 {object} models.ErrorResponse
  63. // @Failure 500 {object} models.ErrorResponse
  64. func createUserAccessToken(w http.ResponseWriter, r *http.Request) {
  65. // Auth request consists of Mac Address and Password (from node that is authorizing
  66. // in case of Master, auth is ignored and mac is set to "mastermac"
  67. var req schema.UserAccessToken
  68. err := json.NewDecoder(r.Body).Decode(&req)
  69. if err != nil {
  70. logger.Log(0, "error decoding request body: ",
  71. err.Error())
  72. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
  73. return
  74. }
  75. if req.Name == "" {
  76. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("name is required"), logic.BadReq))
  77. return
  78. }
  79. if req.UserName == "" {
  80. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), logic.BadReq))
  81. return
  82. }
  83. caller, err := logic.GetUser(r.Header.Get("user"))
  84. if err != nil {
  85. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.UnAuthorized))
  86. return
  87. }
  88. user, err := logic.GetUser(req.UserName)
  89. if err != nil {
  90. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.UnAuthorized))
  91. return
  92. }
  93. if caller.UserName != user.UserName && caller.PlatformRoleID != models.SuperAdminRole {
  94. if caller.PlatformRoleID == models.AdminRole {
  95. if user.PlatformRoleID == models.SuperAdminRole || user.PlatformRoleID == models.AdminRole {
  96. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to create token for user "+user.UserName), logic.Forbidden_Msg))
  97. return
  98. }
  99. } else {
  100. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to create token for user "+user.UserName), logic.Forbidden_Msg))
  101. return
  102. }
  103. }
  104. req.ID = uuid.New().String()
  105. req.CreatedBy = r.Header.Get("user")
  106. req.CreatedAt = time.Now()
  107. jwt, err := logic.CreateUserAccessJwtToken(user.UserName, user.PlatformRoleID, req.ExpiresAt, req.ID)
  108. if jwt == "" {
  109. // very unlikely that err is !nil and no jwt returned, but handle it anyways.
  110. logic.ReturnErrorResponse(
  111. w,
  112. r,
  113. logic.FormatError(errors.New("error creating access token "+err.Error()), logic.Internal),
  114. )
  115. return
  116. }
  117. err = req.Create(r.Context())
  118. if err != nil {
  119. logic.ReturnErrorResponse(
  120. w,
  121. r,
  122. logic.FormatError(errors.New("error creating access token "+err.Error()), logic.Internal),
  123. )
  124. return
  125. }
  126. logic.LogEvent(&models.Event{
  127. Action: models.Create,
  128. Source: models.Subject{
  129. ID: caller.UserName,
  130. Name: caller.UserName,
  131. Type: models.UserSub,
  132. },
  133. TriggeredBy: caller.UserName,
  134. Target: models.Subject{
  135. ID: req.ID,
  136. Name: req.Name,
  137. Type: models.UserAccessTokenSub,
  138. Info: req,
  139. },
  140. Origin: models.Dashboard,
  141. })
  142. logic.ReturnSuccessResponseWithJson(w, r, models.SuccessfulUserLoginResponse{
  143. AuthToken: jwt,
  144. UserName: req.UserName,
  145. }, "api access token has generated for user "+req.UserName)
  146. }
  147. // @Summary Authenticate a user to retrieve an authorization token
  148. // @Router /api/v1/users/{username}/access_token [post]
  149. // @Tags Auth
  150. // @Accept json
  151. // @Param body body models.UserAuthParams true "Authentication parameters"
  152. // @Success 200 {object} models.SuccessResponse
  153. // @Failure 400 {object} models.ErrorResponse
  154. // @Failure 401 {object} models.ErrorResponse
  155. // @Failure 500 {object} models.ErrorResponse
  156. func getUserAccessTokens(w http.ResponseWriter, r *http.Request) {
  157. username := r.URL.Query().Get("username")
  158. if username == "" {
  159. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), "badrequest"))
  160. return
  161. }
  162. logic.ReturnSuccessResponseWithJson(w, r, (&schema.UserAccessToken{UserName: username}).ListByUser(r.Context()), "fetched api access tokens for user "+username)
  163. }
  164. // @Summary Authenticate a user to retrieve an authorization token
  165. // @Router /api/v1/users/{username}/access_token [post]
  166. // @Tags Auth
  167. // @Accept json
  168. // @Param body body models.UserAuthParams true "Authentication parameters"
  169. // @Success 200 {object} models.SuccessResponse
  170. // @Failure 400 {object} models.ErrorResponse
  171. // @Failure 401 {object} models.ErrorResponse
  172. // @Failure 500 {object} models.ErrorResponse
  173. func deleteUserAccessTokens(w http.ResponseWriter, r *http.Request) {
  174. id := r.URL.Query().Get("id")
  175. if id == "" {
  176. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("id is required"), "badrequest"))
  177. return
  178. }
  179. a := schema.UserAccessToken{
  180. ID: id,
  181. }
  182. err := a.Get(r.Context())
  183. if err != nil {
  184. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("token does not exist"), "badrequest"))
  185. return
  186. }
  187. caller, err := logic.GetUser(r.Header.Get("user"))
  188. if err != nil {
  189. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized"))
  190. return
  191. }
  192. user, err := logic.GetUser(a.UserName)
  193. if err != nil {
  194. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized"))
  195. return
  196. }
  197. if caller.UserName != user.UserName && caller.PlatformRoleID != models.SuperAdminRole {
  198. if caller.PlatformRoleID == models.AdminRole {
  199. if user.PlatformRoleID == models.SuperAdminRole || user.PlatformRoleID == models.AdminRole {
  200. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to delete token of user "+user.UserName), logic.Forbidden_Msg))
  201. return
  202. }
  203. } else {
  204. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to delete token of user "+user.UserName), logic.Forbidden_Msg))
  205. return
  206. }
  207. }
  208. err = (&schema.UserAccessToken{ID: id}).Delete(r.Context())
  209. if err != nil {
  210. logic.ReturnErrorResponse(
  211. w,
  212. r,
  213. logic.FormatError(errors.New("error deleting access token "+err.Error()), "internal"),
  214. )
  215. return
  216. }
  217. logic.LogEvent(&models.Event{
  218. Action: models.Delete,
  219. Source: models.Subject{
  220. ID: caller.UserName,
  221. Name: caller.UserName,
  222. Type: models.UserSub,
  223. },
  224. TriggeredBy: caller.UserName,
  225. Target: models.Subject{
  226. ID: a.ID,
  227. Name: a.Name,
  228. Type: models.UserAccessTokenSub,
  229. Info: a,
  230. },
  231. Origin: models.Dashboard,
  232. })
  233. logic.ReturnSuccessResponseWithJson(w, r, nil, "revoked access token")
  234. }
  235. // @Summary Authenticate a user to retrieve an authorization token
  236. // @Router /api/users/adm/authenticate [post]
  237. // @Tags Auth
  238. // @Accept json
  239. // @Param body body models.UserAuthParams true "Authentication parameters"
  240. // @Success 200 {object} models.SuccessResponse
  241. // @Failure 400 {object} models.ErrorResponse
  242. // @Failure 401 {object} models.ErrorResponse
  243. // @Failure 500 {object} models.ErrorResponse
  244. func authenticateUser(response http.ResponseWriter, request *http.Request) {
  245. appName := request.Header.Get("X-Application-Name")
  246. if appName == "" {
  247. appName = logic.NetmakerDesktopApp
  248. }
  249. // Auth request consists of Mac Address and Password (from node that is authorizing
  250. // in case of Master, auth is ignored and mac is set to "mastermac"
  251. var authRequest models.UserAuthParams
  252. var errorResponse = models.ErrorResponse{
  253. Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
  254. }
  255. decoder := json.NewDecoder(request.Body)
  256. decoderErr := decoder.Decode(&authRequest)
  257. defer request.Body.Close()
  258. if decoderErr != nil {
  259. logger.Log(0, "error decoding request body: ",
  260. decoderErr.Error())
  261. logic.ReturnErrorResponse(response, request, errorResponse)
  262. return
  263. }
  264. user, err := logic.GetUser(authRequest.UserName)
  265. if err != nil {
  266. logger.Log(0, authRequest.UserName, "user validation failed: ",
  267. err.Error())
  268. logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized"))
  269. return
  270. }
  271. if logic.IsOauthUser(user) == nil {
  272. logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("user is registered via SSO"), "badrequest"))
  273. return
  274. }
  275. if user.AccountDisabled {
  276. err = errors.New("user account disabled")
  277. logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized"))
  278. return
  279. }
  280. if !user.IsSuperAdmin && !logic.IsBasicAuthEnabled() {
  281. logic.ReturnErrorResponse(
  282. response,
  283. request,
  284. logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
  285. )
  286. return
  287. }
  288. if val := request.Header.Get("From-Ui"); val == "true" {
  289. // request came from UI, if normal user block Login
  290. role, err := logic.GetRole(user.PlatformRoleID)
  291. if err != nil {
  292. logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("access denied to dashboard"), "unauthorized"))
  293. return
  294. }
  295. if role.DenyDashboardAccess {
  296. logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("access denied to dashboard"), "unauthorized"))
  297. return
  298. }
  299. // log user activity
  300. logic.LogEvent(&models.Event{
  301. Action: models.Login,
  302. Source: models.Subject{
  303. ID: user.UserName,
  304. Name: user.UserName,
  305. Type: models.UserSub,
  306. },
  307. TriggeredBy: user.UserName,
  308. Target: models.Subject{
  309. ID: models.DashboardSub.String(),
  310. Name: models.DashboardSub.String(),
  311. Type: models.DashboardSub,
  312. },
  313. Origin: models.Dashboard,
  314. })
  315. } else {
  316. logic.LogEvent(&models.Event{
  317. Action: models.Login,
  318. Source: models.Subject{
  319. ID: user.UserName,
  320. Name: user.UserName,
  321. Type: models.UserSub,
  322. },
  323. TriggeredBy: user.UserName,
  324. Target: models.Subject{
  325. ID: models.ClientAppSub.String(),
  326. Name: models.ClientAppSub.String(),
  327. Type: models.ClientAppSub,
  328. },
  329. Origin: models.ClientApp,
  330. })
  331. }
  332. username := authRequest.UserName
  333. jwt, err := logic.VerifyAuthRequest(authRequest, appName)
  334. if err != nil {
  335. logger.Log(0, username, "user validation failed: ",
  336. err.Error())
  337. logic.ReturnErrorResponse(response, request, logic.FormatError(err, "badrequest"))
  338. return
  339. }
  340. if jwt == "" {
  341. // very unlikely that err is !nil and no jwt returned, but handle it anyways.
  342. logger.Log(0, username, "jwt token is empty")
  343. logic.ReturnErrorResponse(
  344. response,
  345. request,
  346. logic.FormatError(errors.New("no token returned"), "internal"),
  347. )
  348. return
  349. }
  350. var successResponse models.SuccessResponse
  351. if user.IsMFAEnabled {
  352. successResponse = models.SuccessResponse{
  353. Code: http.StatusOK,
  354. Message: "W1R3: TOTP required",
  355. Response: models.PartialUserLoginResponse{
  356. UserName: username,
  357. PreAuthToken: jwt,
  358. },
  359. }
  360. } else {
  361. successResponse = models.SuccessResponse{
  362. Code: http.StatusOK,
  363. Message: "W1R3: Device " + username + " Authorized",
  364. Response: models.SuccessfulUserLoginResponse{
  365. UserName: username,
  366. AuthToken: jwt,
  367. },
  368. }
  369. }
  370. // Send back the JWT
  371. successJSONResponse, jsonError := json.Marshal(successResponse)
  372. if jsonError != nil {
  373. logger.Log(0, username,
  374. "error marshalling resp: ", jsonError.Error())
  375. logic.ReturnErrorResponse(response, request, errorResponse)
  376. return
  377. }
  378. logger.Log(2, username, "was authenticated")
  379. response.Header().Set("Content-Type", "application/json")
  380. response.Write(successJSONResponse)
  381. go func() {
  382. if servercfg.IsPro {
  383. // enable all associeated clients for the user
  384. clients, err := logic.GetAllExtClients()
  385. if err != nil {
  386. slog.Error("error getting clients: ", "error", err)
  387. return
  388. }
  389. for _, client := range clients {
  390. if client.OwnerID == username && !client.Enabled {
  391. slog.Info(
  392. fmt.Sprintf(
  393. "enabling ext client %s for user %s due to RAC autodisabling feature",
  394. client.ClientID,
  395. client.OwnerID,
  396. ),
  397. )
  398. if newClient, err := logic.ToggleExtClientConnectivity(&client, true); err != nil {
  399. slog.Error(
  400. "error enabling ext client in RAC autodisable hook",
  401. "error",
  402. err,
  403. )
  404. continue // dont return but try for other clients
  405. } else {
  406. // publish peer update to ingress gateway
  407. if ingressNode, err := logic.GetNodeByID(newClient.IngressGatewayID); err == nil {
  408. if err = mq.PublishPeerUpdate(false); err != nil {
  409. slog.Error("error updating ext clients on", "ingress", ingressNode.ID.String(), "err", err.Error())
  410. }
  411. }
  412. }
  413. }
  414. }
  415. }
  416. }()
  417. }
  418. // @Summary Initiate setting up TOTP 2FA for a user.
  419. // @Router /api/users/auth/init-totp [post]
  420. // @Tags Auth
  421. // @Success 200 {object} models.SuccessResponse
  422. // @Failure 400 {object} models.ErrorResponse
  423. // @Failure 500 {object} models.ErrorResponse
  424. func initiateTOTPSetup(w http.ResponseWriter, r *http.Request) {
  425. username := r.Header.Get("user")
  426. user, err := logic.GetUser(username)
  427. if err != nil {
  428. logger.Log(0, "failed to get user: ", err.Error())
  429. err = fmt.Errorf("user not found: %v", err)
  430. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  431. return
  432. }
  433. if user.AuthType == models.OAuth {
  434. err = fmt.Errorf("auth type is %s, cannot process totp setup", user.AuthType)
  435. logger.Log(0, err.Error())
  436. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  437. return
  438. }
  439. key, err := totp.Generate(totp.GenerateOpts{
  440. Issuer: "Netmaker",
  441. AccountName: username,
  442. })
  443. if err != nil {
  444. err = fmt.Errorf("failed to generate totp key: %v", err)
  445. logger.Log(0, err.Error())
  446. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  447. return
  448. }
  449. qrCodeImg, err := key.Image(200, 200)
  450. if err != nil {
  451. err = fmt.Errorf("failed to generate totp key: %v", err)
  452. logger.Log(0, err.Error())
  453. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  454. return
  455. }
  456. var qrCodePng bytes.Buffer
  457. err = png.Encode(&qrCodePng, qrCodeImg)
  458. if err != nil {
  459. err = fmt.Errorf("failed to generate totp key: %v", err)
  460. logger.Log(0, err.Error())
  461. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  462. return
  463. }
  464. qrCode := "data:image/png;base64," + base64.StdEncoding.EncodeToString(qrCodePng.Bytes())
  465. logic.ReturnSuccessResponseWithJson(w, r, models.TOTPInitiateResponse{
  466. OTPAuthURL: key.URL(),
  467. OTPAuthURLSignature: logic.GenerateOTPAuthURLSignature(key.URL()),
  468. QRCode: qrCode,
  469. }, "totp setup initiated")
  470. }
  471. // @Summary Verify and complete setting up TOTP 2FA for a user.
  472. // @Router /api/users/auth/complete-totp [post]
  473. // @Tags Auth
  474. // @Param body body models.UserTOTPVerificationParams true "TOTP verification parameters"
  475. // @Success 200 {object} models.SuccessResponse
  476. // @Failure 400 {object} models.ErrorResponse
  477. // @Failure 500 {object} models.ErrorResponse
  478. func completeTOTPSetup(w http.ResponseWriter, r *http.Request) {
  479. username := r.Header.Get("user")
  480. var req models.UserTOTPVerificationParams
  481. err := json.NewDecoder(r.Body).Decode(&req)
  482. if err != nil {
  483. logger.Log(0, "failed to decode request body: ", err.Error())
  484. err = fmt.Errorf("invalid request body: %v", err)
  485. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  486. return
  487. }
  488. if !logic.VerifyOTPAuthURL(req.OTPAuthURL, req.OTPAuthURLSignature) {
  489. err = fmt.Errorf("otp auth url signature mismatch")
  490. logger.Log(0, err.Error())
  491. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  492. return
  493. }
  494. user, err := logic.GetUser(username)
  495. if err != nil {
  496. logger.Log(0, "failed to get user: ", err.Error())
  497. err = fmt.Errorf("user not found: %v", err)
  498. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  499. return
  500. }
  501. if user.AuthType == models.OAuth {
  502. err = fmt.Errorf("auth type is %s, cannot process totp setup", user.AuthType)
  503. logger.Log(0, err.Error())
  504. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  505. return
  506. }
  507. otpAuthURL, err := otp.NewKeyFromURL(req.OTPAuthURL)
  508. if err != nil {
  509. err = fmt.Errorf("error parsing otp auth url: %v", err)
  510. logger.Log(0, err.Error())
  511. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  512. return
  513. }
  514. totpSecret := otpAuthURL.Secret()
  515. if totp.Validate(req.TOTP, totpSecret) {
  516. user.IsMFAEnabled = true
  517. user.TOTPSecret = totpSecret
  518. err = logic.UpsertUser(*user)
  519. if err != nil {
  520. err = fmt.Errorf("error upserting user: %v", err)
  521. logger.Log(0, err.Error())
  522. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  523. return
  524. }
  525. logic.ReturnSuccessResponse(w, r, fmt.Sprintf("totp setup complete for user %s", username))
  526. } else {
  527. err = fmt.Errorf("cannot setup totp for user %s: invalid otp", username)
  528. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  529. }
  530. }
  531. // @Summary Verify a user's TOTP token.
  532. // @Router /api/users/auth/verify-totp [post]
  533. // @Tags Auth
  534. // @Accept json
  535. // @Param body body models.UserTOTPVerificationParams true "TOTP verification parameters"
  536. // @Success 200 {object} models.SuccessResponse
  537. // @Failure 400 {object} models.ErrorResponse
  538. // @Failure 401 {object} models.ErrorResponse
  539. // @Failure 500 {object} models.ErrorResponse
  540. func verifyTOTP(w http.ResponseWriter, r *http.Request) {
  541. username := r.Header.Get("user")
  542. appName := r.Header.Get("X-Application-Name")
  543. if appName == "" {
  544. appName = logic.NetmakerDesktopApp
  545. }
  546. var req models.UserTOTPVerificationParams
  547. err := json.NewDecoder(r.Body).Decode(&req)
  548. if err != nil {
  549. logger.Log(0, "failed to decode request body: ", err.Error())
  550. err = fmt.Errorf("invalid request body: %v", err)
  551. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  552. return
  553. }
  554. user, err := logic.GetUser(username)
  555. if err != nil {
  556. logger.Log(0, "failed to get user: ", err.Error())
  557. err = fmt.Errorf("user not found: %v", err)
  558. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  559. return
  560. }
  561. if !user.IsMFAEnabled {
  562. err = fmt.Errorf("mfa is disabled for user(%s), cannot process totp verification", username)
  563. logger.Log(0, err.Error())
  564. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  565. return
  566. }
  567. if totp.Validate(req.TOTP, user.TOTPSecret) {
  568. jwt, err := logic.CreateUserJWT(user.UserName, user.PlatformRoleID, appName)
  569. if err != nil {
  570. err = fmt.Errorf("error creating token: %v", err)
  571. logger.Log(0, err.Error())
  572. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  573. return
  574. }
  575. // update last login time
  576. user.LastLoginTime = time.Now().UTC()
  577. err = logic.UpsertUser(*user)
  578. if err != nil {
  579. err = fmt.Errorf("error upserting user: %v", err)
  580. logger.Log(0, err.Error())
  581. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  582. return
  583. }
  584. logic.ReturnSuccessResponseWithJson(w, r, models.SuccessfulUserLoginResponse{
  585. UserName: username,
  586. AuthToken: jwt,
  587. }, "W1R3: User "+username+" Authorized")
  588. } else {
  589. err = fmt.Errorf("invalid otp")
  590. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized"))
  591. }
  592. }
  593. // @Summary Check if the server has a super admin
  594. // @Router /api/users/adm/hassuperadmin [get]
  595. // @Tags Users
  596. // @Success 200 {object} bool
  597. // @Failure 500 {object} models.ErrorResponse
  598. func hasSuperAdmin(w http.ResponseWriter, r *http.Request) {
  599. w.Header().Set("Content-Type", "application/json")
  600. hasSuperAdmin, err := logic.HasSuperAdmin()
  601. if err != nil {
  602. logger.Log(0, "failed to check for admin: ", err.Error())
  603. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  604. return
  605. }
  606. json.NewEncoder(w).Encode(hasSuperAdmin)
  607. }
  608. // @Summary Get an individual user
  609. // @Router /api/users/{username} [get]
  610. // @Tags Users
  611. // @Param username path string true "Username of the user to fetch"
  612. // @Success 200 {object} models.User
  613. // @Failure 500 {object} models.ErrorResponse
  614. func getUser(w http.ResponseWriter, r *http.Request) {
  615. // set header.
  616. w.Header().Set("Content-Type", "application/json")
  617. var params = mux.Vars(r)
  618. usernameFetched := params["username"]
  619. user, err := logic.GetReturnUser(usernameFetched)
  620. if err != nil {
  621. logger.Log(0, usernameFetched, "failed to fetch user: ", err.Error())
  622. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  623. return
  624. }
  625. logger.Log(2, r.Header.Get("user"), "fetched user", usernameFetched)
  626. json.NewEncoder(w).Encode(user)
  627. }
  628. // @Summary Enable a user's account
  629. // @Router /api/users/{username}/enable [post]
  630. // @Tags Users
  631. // @Param username path string true "Username of the user to enable"
  632. // @Success 200 {object} models.SuccessResponse
  633. // @Failure 400 {object} models.ErrorResponse
  634. // @Failure 500 {object} models.ErrorResponse
  635. func enableUserAccount(w http.ResponseWriter, r *http.Request) {
  636. username := mux.Vars(r)["username"]
  637. user, err := logic.GetUser(username)
  638. if err != nil {
  639. logger.Log(0, "failed to fetch user: ", err.Error())
  640. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  641. return
  642. }
  643. user.AccountDisabled = false
  644. err = logic.UpsertUser(*user)
  645. if err != nil {
  646. logger.Log(0, "failed to enable user account: ", err.Error())
  647. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  648. }
  649. logic.ReturnSuccessResponse(w, r, "user account enabled")
  650. }
  651. // @Summary Disable a user's account
  652. // @Router /api/users/{username}/disable [post]
  653. // @Tags Users
  654. // @Param username path string true "Username of the user to disable"
  655. // @Success 200 {object} models.SuccessResponse
  656. // @Failure 400 {object} models.ErrorResponse
  657. // @Failure 500 {object} models.ErrorResponse
  658. func disableUserAccount(w http.ResponseWriter, r *http.Request) {
  659. username := mux.Vars(r)["username"]
  660. user, err := logic.GetUser(username)
  661. if err != nil {
  662. logger.Log(0, "failed to fetch user: ", err.Error())
  663. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  664. return
  665. }
  666. if user.PlatformRoleID == models.SuperAdminRole {
  667. err = errors.New("cannot disable super-admin user account")
  668. logger.Log(0, err.Error())
  669. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  670. return
  671. }
  672. user.AccountDisabled = true
  673. err = logic.UpsertUser(*user)
  674. if err != nil {
  675. logger.Log(0, "failed to disable user account: ", err.Error())
  676. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  677. }
  678. logic.ReturnSuccessResponse(w, r, "user account disabled")
  679. }
  680. // @Summary Get a user's preferences and settings
  681. // @Router /api/users/{username}/settings [get]
  682. // @Tags Users
  683. // @Param username path string true "Username of the user"
  684. // @Success 200 {object} models.SuccessResponse
  685. func getUserSettings(w http.ResponseWriter, r *http.Request) {
  686. userID := r.Header.Get("user")
  687. userSettings := logic.GetUserSettings(userID)
  688. logic.ReturnSuccessResponseWithJson(w, r, userSettings, "fetched user settings")
  689. }
  690. // @Summary Update a user's preferences and settings
  691. // @Router /api/users/{username}/settings [put]
  692. // @Tags Users
  693. // @Param username path string true "Username of the user"
  694. // @Success 200 {object} models.SuccessResponse
  695. // @Failure 400 {object} models.ErrorResponse
  696. // @Failure 500 {object} models.ErrorResponse
  697. func updateUserSettings(w http.ResponseWriter, r *http.Request) {
  698. userID := r.Header.Get("user")
  699. var req models.UserSettings
  700. err := json.NewDecoder(r.Body).Decode(&req)
  701. if err != nil {
  702. logger.Log(0, "failed to decode request body: ", err.Error())
  703. err = fmt.Errorf("invalid request body: %v", err)
  704. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  705. return
  706. }
  707. err = logic.UpsertUserSettings(userID, req)
  708. if err != nil {
  709. err = fmt.Errorf("failed to update user settings: %v", err.Error())
  710. logger.Log(0, err.Error())
  711. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  712. return
  713. }
  714. logic.ReturnSuccessResponseWithJson(w, r, req, "updated user settings")
  715. }
  716. // swagger:route GET /api/v1/users user getUserV1
  717. //
  718. // Get an individual user with role info.
  719. //
  720. // Schemes: https
  721. //
  722. // Security:
  723. // oauth
  724. //
  725. // Responses:
  726. // 200: ReturnUserWithRolesAndGroups
  727. func getUserV1(w http.ResponseWriter, r *http.Request) {
  728. // set header.
  729. w.Header().Set("Content-Type", "application/json")
  730. usernameFetched := r.URL.Query().Get("username")
  731. if usernameFetched == "" {
  732. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), "badrequest"))
  733. return
  734. }
  735. user, err := logic.GetReturnUser(usernameFetched)
  736. if err != nil {
  737. logger.Log(0, usernameFetched, "failed to fetch user: ", err.Error())
  738. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  739. return
  740. }
  741. userRoleTemplate, err := logic.GetRole(user.PlatformRoleID)
  742. if err != nil {
  743. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  744. return
  745. }
  746. resp := models.ReturnUserWithRolesAndGroups{
  747. ReturnUser: user,
  748. PlatformRole: userRoleTemplate,
  749. UserGroups: map[models.UserGroupID]models.UserGroup{},
  750. }
  751. for gId := range user.UserGroups {
  752. grp, err := logic.GetUserGroup(gId)
  753. if err != nil {
  754. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  755. return
  756. }
  757. resp.UserGroups[gId] = grp
  758. }
  759. logger.Log(2, r.Header.Get("user"), "fetched user", usernameFetched)
  760. logic.ReturnSuccessResponseWithJson(w, r, resp, "fetched user with role info")
  761. }
  762. // swagger:route GET /api/users user getUsers
  763. //
  764. // Get all users.
  765. //
  766. // Schemes: https
  767. //
  768. // Security:
  769. // oauth
  770. //
  771. // Responses:
  772. // 200: userBodyResponse
  773. func getUsers(w http.ResponseWriter, r *http.Request) {
  774. // set header.
  775. w.Header().Set("Content-Type", "application/json")
  776. users, err := logic.GetUsers()
  777. if err != nil {
  778. logger.Log(0, "failed to fetch users: ", err.Error())
  779. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  780. return
  781. }
  782. logic.SortUsers(users[:])
  783. logger.Log(2, r.Header.Get("user"), "fetched users")
  784. json.NewEncoder(w).Encode(users)
  785. }
  786. // @Summary Create a super admin
  787. // @Router /api/users/adm/createsuperadmin [post]
  788. // @Tags Users
  789. // @Param body body models.User true "User details"
  790. // @Success 200 {object} models.User
  791. // @Failure 400 {object} models.ErrorResponse
  792. // @Failure 500 {object} models.ErrorResponse
  793. func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
  794. w.Header().Set("Content-Type", "application/json")
  795. var u models.User
  796. err := json.NewDecoder(r.Body).Decode(&u)
  797. if err != nil {
  798. slog.Error("error decoding request body", "error", err.Error())
  799. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  800. return
  801. }
  802. if !logic.IsBasicAuthEnabled() {
  803. logic.ReturnErrorResponse(
  804. w,
  805. r,
  806. logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
  807. )
  808. return
  809. }
  810. err = logic.CreateSuperAdmin(&u)
  811. if err != nil {
  812. slog.Error("failed to create admin", "error", err.Error())
  813. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  814. return
  815. }
  816. logger.Log(1, u.UserName, "was made a super admin")
  817. json.NewEncoder(w).Encode(logic.ToReturnUser(u))
  818. }
  819. // @Summary Transfer super admin role to another admin user
  820. // @Router /api/users/adm/transfersuperadmin/{username} [post]
  821. // @Tags Users
  822. // @Param username path string true "Username of the user to transfer super admin role"
  823. // @Success 200 {object} models.User
  824. // @Failure 403 {object} models.ErrorResponse
  825. // @Failure 500 {object} models.ErrorResponse
  826. func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
  827. w.Header().Set("Content-Type", "application/json")
  828. caller, err := logic.GetUser(r.Header.Get("user"))
  829. if err != nil {
  830. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  831. }
  832. if caller.PlatformRoleID != models.SuperAdminRole {
  833. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only superadmin can assign the superadmin role to another user"), "forbidden"))
  834. return
  835. }
  836. var params = mux.Vars(r)
  837. username := params["username"]
  838. u, err := logic.GetUser(username)
  839. if err != nil {
  840. slog.Error("error getting user", "user", u.UserName, "error", err.Error())
  841. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  842. return
  843. }
  844. if u.PlatformRoleID != models.AdminRole {
  845. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only admins can be promoted to superadmin role"), "forbidden"))
  846. return
  847. }
  848. if !logic.IsBasicAuthEnabled() {
  849. logic.ReturnErrorResponse(
  850. w,
  851. r,
  852. logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
  853. )
  854. return
  855. }
  856. u.PlatformRoleID = models.SuperAdminRole
  857. err = logic.UpsertUser(*u)
  858. if err != nil {
  859. slog.Error("error updating user to superadmin: ", "user", u.UserName, "error", err.Error())
  860. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  861. return
  862. }
  863. caller.PlatformRoleID = models.AdminRole
  864. err = logic.UpsertUser(*caller)
  865. if err != nil {
  866. slog.Error("error demoting user to admin: ", "user", caller.UserName, "error", err.Error())
  867. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  868. return
  869. }
  870. slog.Info("user was made a super admin", "user", u.UserName)
  871. json.NewEncoder(w).Encode(logic.ToReturnUser(*u))
  872. }
  873. // @Summary Create a user
  874. // @Router /api/users/{username} [post]
  875. // @Tags Users
  876. // @Param username path string true "Username of the user to create"
  877. // @Param body body models.User true "User details"
  878. // @Success 200 {object} models.User
  879. // @Failure 400 {object} models.ErrorResponse
  880. // @Failure 403 {object} models.ErrorResponse
  881. // @Failure 500 {object} models.ErrorResponse
  882. func createUser(w http.ResponseWriter, r *http.Request) {
  883. w.Header().Set("Content-Type", "application/json")
  884. caller, err := logic.GetUser(r.Header.Get("user"))
  885. if err != nil {
  886. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  887. return
  888. }
  889. var user models.User
  890. err = json.NewDecoder(r.Body).Decode(&user)
  891. if err != nil {
  892. logger.Log(0, user.UserName, "error decoding request body: ",
  893. err.Error())
  894. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  895. return
  896. }
  897. if !servercfg.IsPro {
  898. user.PlatformRoleID = models.AdminRole
  899. }
  900. if user.UserName == logic.MasterUser {
  901. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username not allowed"), "badrequest"))
  902. return
  903. }
  904. if user.PlatformRoleID == "" {
  905. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("platform role is missing"), "badrequest"))
  906. return
  907. }
  908. userRole, err := logic.GetRole(user.PlatformRoleID)
  909. if err != nil {
  910. err = errors.New("error fetching role " + user.PlatformRoleID.String() + " " + err.Error())
  911. slog.Error("error creating new user: ", "user", user.UserName, "error", err)
  912. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  913. return
  914. }
  915. if userRole.ID == models.SuperAdminRole {
  916. err = errors.New("additional superadmins cannot be created")
  917. slog.Error("error creating new user: ", "user", user.UserName, "error", err)
  918. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  919. return
  920. }
  921. if caller.PlatformRoleID != models.SuperAdminRole && user.PlatformRoleID == models.AdminRole {
  922. err = errors.New("only superadmin can create admin users")
  923. slog.Error("error creating new user: ", "user", user.UserName, "error", err)
  924. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  925. return
  926. }
  927. if !servercfg.IsPro && user.PlatformRoleID != models.AdminRole {
  928. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("non-admins users can only be created on Pro version"), "forbidden"))
  929. return
  930. }
  931. err = logic.CreateUser(&user)
  932. if err != nil {
  933. slog.Error("error creating new user: ", "user", user.UserName, "error", err.Error())
  934. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  935. return
  936. }
  937. logic.LogEvent(&models.Event{
  938. Action: models.Create,
  939. Source: models.Subject{
  940. ID: caller.UserName,
  941. Name: caller.UserName,
  942. Type: models.UserSub,
  943. },
  944. TriggeredBy: caller.UserName,
  945. Target: models.Subject{
  946. ID: user.UserName,
  947. Name: user.UserName,
  948. Type: models.UserSub,
  949. Info: user,
  950. },
  951. Origin: models.Dashboard,
  952. })
  953. logic.DeleteUserInvite(user.UserName)
  954. logic.DeletePendingUser(user.UserName)
  955. go mq.PublishPeerUpdate(false)
  956. slog.Info("user was created", "username", user.UserName)
  957. json.NewEncoder(w).Encode(logic.ToReturnUser(user))
  958. }
  959. // @Summary Update a user
  960. // @Router /api/users/{username} [put]
  961. // @Tags Users
  962. // @Param username path string true "Username of the user to update"
  963. // @Param body body models.User true "User details"
  964. // @Success 200 {object} models.User
  965. // @Failure 400 {object} models.ErrorResponse
  966. // @Failure 403 {object} models.ErrorResponse
  967. // @Failure 500 {object} models.ErrorResponse
  968. func updateUser(w http.ResponseWriter, r *http.Request) {
  969. w.Header().Set("Content-Type", "application/json")
  970. var params = mux.Vars(r)
  971. // start here
  972. var caller *models.User
  973. var err error
  974. var ismaster bool
  975. if r.Header.Get("user") == logic.MasterUser {
  976. ismaster = true
  977. } else {
  978. caller, err = logic.GetUser(r.Header.Get("user"))
  979. if err != nil {
  980. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  981. }
  982. }
  983. username := params["username"]
  984. user, err := logic.GetUser(username)
  985. if err != nil {
  986. logger.Log(0, username,
  987. "failed to update user info: ", err.Error())
  988. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  989. return
  990. }
  991. var userchange models.User
  992. // we decode our body request params
  993. err = json.NewDecoder(r.Body).Decode(&userchange)
  994. if err != nil {
  995. slog.Error("failed to decode body", "error ", err.Error())
  996. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  997. return
  998. }
  999. if user.UserName != userchange.UserName {
  1000. logic.ReturnErrorResponse(
  1001. w,
  1002. r,
  1003. logic.FormatError(
  1004. errors.New("user in param and request body not matching"),
  1005. "badrequest",
  1006. ),
  1007. )
  1008. return
  1009. }
  1010. selfUpdate := false
  1011. if !ismaster && caller.UserName == user.UserName {
  1012. selfUpdate = true
  1013. }
  1014. if !ismaster && !selfUpdate {
  1015. if caller.PlatformRoleID == models.AdminRole && user.PlatformRoleID == models.SuperAdminRole {
  1016. slog.Error("non-superadmin user", "caller", caller.UserName, "attempted to update superadmin user", username)
  1017. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
  1018. return
  1019. }
  1020. if caller.PlatformRoleID != models.AdminRole && caller.PlatformRoleID != models.SuperAdminRole {
  1021. slog.Error("operation not allowed", "caller", caller.UserName, "attempted to update user", username)
  1022. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
  1023. return
  1024. }
  1025. if caller.PlatformRoleID == models.AdminRole && user.PlatformRoleID == models.AdminRole {
  1026. slog.Error("an admin user does not have permissions to update another admin user", "caller", caller.UserName, "attempted to update admin user", username)
  1027. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("an admin user does not have permissions to update another admin user"), "forbidden"))
  1028. return
  1029. }
  1030. if caller.PlatformRoleID == models.AdminRole && userchange.PlatformRoleID == models.AdminRole {
  1031. err = errors.New("an admin user does not have permissions to assign the admin role to another user")
  1032. slog.Error(
  1033. "failed to update user",
  1034. "caller",
  1035. caller.UserName,
  1036. "attempted to update user",
  1037. username,
  1038. "error",
  1039. err,
  1040. )
  1041. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  1042. return
  1043. }
  1044. }
  1045. if !ismaster && selfUpdate {
  1046. if user.PlatformRoleID != userchange.PlatformRoleID {
  1047. slog.Error("user cannot change his own role", "caller", caller.UserName, "attempted to update user role", username)
  1048. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"))
  1049. return
  1050. }
  1051. if logic.IsMFAEnforced() && user.IsMFAEnabled && !userchange.IsMFAEnabled {
  1052. err = errors.New("mfa is enforced, user cannot unset their own mfa")
  1053. slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)
  1054. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  1055. return
  1056. }
  1057. if servercfg.IsPro {
  1058. // user cannot update his own roles and groups
  1059. if len(user.NetworkRoles) != len(userchange.NetworkRoles) || !reflect.DeepEqual(user.NetworkRoles, userchange.NetworkRoles) {
  1060. err = errors.New("user cannot update self update their network roles")
  1061. slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)
  1062. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  1063. return
  1064. }
  1065. // user cannot update his own roles and groups
  1066. if len(user.UserGroups) != len(userchange.UserGroups) || !reflect.DeepEqual(user.UserGroups, userchange.UserGroups) {
  1067. err = errors.New("user cannot update self update their groups")
  1068. slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)
  1069. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  1070. return
  1071. }
  1072. }
  1073. }
  1074. if ismaster {
  1075. if user.PlatformRoleID != models.SuperAdminRole && userchange.PlatformRoleID == models.SuperAdminRole {
  1076. slog.Error("operation not allowed", "caller", logic.MasterUser, "attempted to update user role to superadmin", username)
  1077. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("attempted to update user role to superadmin"), "forbidden"))
  1078. return
  1079. }
  1080. }
  1081. if logic.IsOauthUser(user) == nil && userchange.Password != "" {
  1082. err := fmt.Errorf("cannot update user's password for an oauth user %s", username)
  1083. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  1084. return
  1085. }
  1086. logic.AddGlobalNetRolesToAdmins(&userchange)
  1087. if userchange.PlatformRoleID != user.PlatformRoleID || !logic.CompareMaps(user.UserGroups, userchange.UserGroups) {
  1088. (&schema.UserAccessToken{UserName: user.UserName}).DeleteAllUserTokens(r.Context())
  1089. }
  1090. oldUser := *user
  1091. if ismaster {
  1092. caller = &models.User{
  1093. UserName: logic.MasterUser,
  1094. }
  1095. }
  1096. e := models.Event{
  1097. Action: models.Update,
  1098. Source: models.Subject{
  1099. ID: caller.UserName,
  1100. Name: caller.UserName,
  1101. Type: models.UserSub,
  1102. },
  1103. TriggeredBy: caller.UserName,
  1104. Target: models.Subject{
  1105. ID: user.UserName,
  1106. Name: user.UserName,
  1107. Type: models.UserSub,
  1108. },
  1109. Diff: models.Diff{
  1110. Old: oldUser,
  1111. New: userchange,
  1112. },
  1113. Origin: models.Dashboard,
  1114. }
  1115. user, err = logic.UpdateUser(&userchange, user)
  1116. if err != nil {
  1117. logger.Log(0, username,
  1118. "failed to update user info: ", err.Error())
  1119. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  1120. return
  1121. }
  1122. logic.LogEvent(&e)
  1123. go mq.PublishPeerUpdate(false)
  1124. logger.Log(1, username, "was updated")
  1125. json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
  1126. }
  1127. // @Summary Delete a user
  1128. // @Router /api/users/{username} [delete]
  1129. // @Tags Users
  1130. // @Param username path string true "Username of the user to delete"
  1131. // @Success 200 {string} string
  1132. // @Failure 500 {object} models.ErrorResponse
  1133. func deleteUser(w http.ResponseWriter, r *http.Request) {
  1134. // Set header
  1135. w.Header().Set("Content-Type", "application/json")
  1136. // get params
  1137. var params = mux.Vars(r)
  1138. caller, err := logic.GetUser(r.Header.Get("user"))
  1139. if err != nil {
  1140. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1141. }
  1142. callerUserRole, err := logic.GetRole(caller.PlatformRoleID)
  1143. if err != nil {
  1144. slog.Error("failed to get role ", "role", callerUserRole.ID, "error", err)
  1145. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1146. return
  1147. }
  1148. username := params["username"]
  1149. user, err := logic.GetUser(username)
  1150. if err != nil {
  1151. logger.Log(0, username,
  1152. "failed to update user info: ", err.Error())
  1153. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1154. return
  1155. }
  1156. userRole, err := logic.GetRole(user.PlatformRoleID)
  1157. if err != nil {
  1158. slog.Error("failed to get role ", "role", userRole.ID, "error", err)
  1159. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1160. return
  1161. }
  1162. if userRole.ID == models.SuperAdminRole {
  1163. slog.Error(
  1164. "failed to delete user: ", "user", username, "error", "superadmin cannot be deleted")
  1165. logic.ReturnErrorResponse(
  1166. w,
  1167. r,
  1168. logic.FormatError(fmt.Errorf("superadmin cannot be deleted"), "internal"),
  1169. )
  1170. return
  1171. }
  1172. if callerUserRole.ID != models.SuperAdminRole {
  1173. if callerUserRole.ID == models.AdminRole && userRole.ID == models.AdminRole {
  1174. slog.Error(
  1175. "failed to delete user: ",
  1176. "user",
  1177. username,
  1178. "error",
  1179. "admin cannot delete another admin user, including oneself",
  1180. )
  1181. logic.ReturnErrorResponse(
  1182. w,
  1183. r,
  1184. logic.FormatError(
  1185. fmt.Errorf("admin cannot delete another admin user, including oneself"),
  1186. "internal",
  1187. ),
  1188. )
  1189. return
  1190. }
  1191. }
  1192. if user.AuthType == models.OAuth || user.ExternalIdentityProviderID != "" {
  1193. err = fmt.Errorf("cannot delete idp user %s", username)
  1194. logger.Log(0, username, "failed to delete user: ", err.Error())
  1195. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  1196. return
  1197. }
  1198. err = logic.DeleteUser(username)
  1199. if err != nil {
  1200. logger.Log(0, username,
  1201. "failed to delete user: ", err.Error())
  1202. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1203. return
  1204. }
  1205. logic.LogEvent(&models.Event{
  1206. Action: models.Delete,
  1207. Source: models.Subject{
  1208. ID: caller.UserName,
  1209. Name: caller.UserName,
  1210. Type: models.UserSub,
  1211. },
  1212. TriggeredBy: caller.UserName,
  1213. Target: models.Subject{
  1214. ID: user.UserName,
  1215. Name: user.UserName,
  1216. Type: models.UserSub,
  1217. },
  1218. Origin: models.Dashboard,
  1219. })
  1220. // check and delete extclient with this ownerID
  1221. go func() {
  1222. extclients, err := logic.GetAllExtClients()
  1223. if err != nil {
  1224. slog.Error("failed to get extclients", "error", err)
  1225. return
  1226. }
  1227. for _, extclient := range extclients {
  1228. if extclient.OwnerID == user.UserName {
  1229. err = logic.DeleteExtClientAndCleanup(extclient)
  1230. if err != nil {
  1231. slog.Error("failed to delete extclient",
  1232. "id", extclient.ClientID, "owner", username, "error", err)
  1233. } else {
  1234. if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {
  1235. slog.Error("error setting ext peers: " + err.Error())
  1236. }
  1237. }
  1238. }
  1239. }
  1240. _ = logic.DeleteUserInvite(user.UserName)
  1241. mq.PublishPeerUpdate(false)
  1242. if servercfg.IsDNSMode() {
  1243. logic.SetDNS()
  1244. }
  1245. }()
  1246. logger.Log(1, username, "was deleted")
  1247. json.NewEncoder(w).Encode(params["username"] + " deleted.")
  1248. }
  1249. // Called when vpn client dials in to start the auth flow and first stage is to get register URL itself
  1250. func socketHandler(w http.ResponseWriter, r *http.Request) {
  1251. // Upgrade our raw HTTP connection to a websocket based one
  1252. conn, err := upgrader.Upgrade(w, r, nil)
  1253. if err != nil {
  1254. logger.Log(0, "error during connection upgrade for node sign-in:", err.Error())
  1255. return
  1256. }
  1257. if conn == nil {
  1258. logger.Log(0, "failed to establish web-socket connection during node sign-in")
  1259. return
  1260. }
  1261. // Start handling the session
  1262. go auth.SessionHandler(conn)
  1263. }
  1264. // @Summary lists all user roles.
  1265. // @Router /api/v1/user/roles [get]
  1266. // @Tags Users
  1267. // @Param role_id query string true "roleid required to get the role details"
  1268. // @Success 200 {object} []models.UserRolePermissionTemplate
  1269. // @Failure 500 {object} models.ErrorResponse
  1270. func listRoles(w http.ResponseWriter, r *http.Request) {
  1271. var roles []models.UserRolePermissionTemplate
  1272. var err error
  1273. roles, err = logic.ListPlatformRoles()
  1274. if err != nil {
  1275. logic.ReturnErrorResponse(w, r, models.ErrorResponse{
  1276. Code: http.StatusInternalServerError,
  1277. Message: err.Error(),
  1278. })
  1279. return
  1280. }
  1281. logic.ReturnSuccessResponseWithJson(w, r, roles, "successfully fetched user roles permission templates")
  1282. }
  1283. // swagger:route POST /api/v1/user/logout user logout
  1284. //
  1285. // LogOut user.
  1286. //
  1287. // Schemes: https
  1288. //
  1289. // Security:
  1290. // oauth
  1291. //
  1292. // Responses:
  1293. // 200: userBodyResponse
  1294. func logout(w http.ResponseWriter, r *http.Request) {
  1295. // set header.
  1296. w.Header().Set("Content-Type", "application/json")
  1297. userName := r.URL.Query().Get("username")
  1298. user, err := logic.GetUser(userName)
  1299. if err != nil {
  1300. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
  1301. return
  1302. }
  1303. var target models.SubjectType
  1304. if val := r.Header.Get("From-Ui"); val == "true" {
  1305. target = models.DashboardSub
  1306. } else {
  1307. target = models.ClientAppSub
  1308. }
  1309. if target != "" {
  1310. logic.LogEvent(&models.Event{
  1311. Action: models.LogOut,
  1312. Source: models.Subject{
  1313. ID: user.UserName,
  1314. Name: user.UserName,
  1315. Type: models.UserSub,
  1316. },
  1317. TriggeredBy: user.UserName,
  1318. Target: models.Subject{
  1319. ID: target.String(),
  1320. Name: target.String(),
  1321. Type: target,
  1322. },
  1323. Origin: models.Origin(target),
  1324. })
  1325. }
  1326. logic.ReturnSuccessResponse(w, r, "user logged out")
  1327. }