user.go 49 KB

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