user.go 46 KB

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