user.go 47 KB

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