user.go 48 KB

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