user.go 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  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. "net/url"
  13. "reflect"
  14. "time"
  15. "github.com/google/uuid"
  16. "github.com/gorilla/mux"
  17. "github.com/gorilla/websocket"
  18. "github.com/gravitl/netmaker/auth"
  19. "github.com/gravitl/netmaker/logger"
  20. "github.com/gravitl/netmaker/logic"
  21. "github.com/gravitl/netmaker/models"
  22. "github.com/gravitl/netmaker/mq"
  23. "github.com/gravitl/netmaker/schema"
  24. "github.com/gravitl/netmaker/servercfg"
  25. "github.com/pquerna/otp/totp"
  26. "golang.org/x/exp/slog"
  27. )
  28. var (
  29. upgrader = websocket.Upgrader{}
  30. )
  31. var ListRoles = listRoles
  32. func userHandlers(r *mux.Router) {
  33. r.HandleFunc("/api/users/adm/hassuperadmin", hasSuperAdmin).Methods(http.MethodGet)
  34. r.HandleFunc("/api/users/adm/createsuperadmin", createSuperAdmin).Methods(http.MethodPost)
  35. r.HandleFunc("/api/users/adm/transfersuperadmin/{username}", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).
  36. Methods(http.MethodPost)
  37. r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost)
  38. r.HandleFunc("/api/users/auth/init-totp", logic.SecurityCheck(false, http.HandlerFunc(initiateTOTPSetup))).Methods(http.MethodPost)
  39. r.HandleFunc("/api/users/auth/complete-totp", logic.SecurityCheck(false, http.HandlerFunc(completeTOTPSetup))).Methods(http.MethodPost)
  40. r.HandleFunc("/api/users/auth/verify-totp", logic.PreAuthCheck(http.HandlerFunc(verifyTOTP))).Methods(http.MethodPost)
  41. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUser))).Methods(http.MethodPut)
  42. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).Methods(http.MethodPost)
  43. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete)
  44. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)
  45. r.HandleFunc("/api/users/{username}/enable", logic.SecurityCheck(true, http.HandlerFunc(enableUserAccount))).Methods(http.MethodPost)
  46. r.HandleFunc("/api/users/{username}/disable", logic.SecurityCheck(true, http.HandlerFunc(disableUserAccount))).Methods(http.MethodPost)
  47. r.HandleFunc("/api/v1/users", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserV1)))).Methods(http.MethodGet)
  48. r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet)
  49. r.HandleFunc("/api/v1/users/roles", logic.SecurityCheck(true, http.HandlerFunc(ListRoles))).Methods(http.MethodGet)
  50. r.HandleFunc("/api/v1/users/access_token", logic.SecurityCheck(true, http.HandlerFunc(createUserAccessToken))).Methods(http.MethodPost)
  51. r.HandleFunc("/api/v1/users/access_token", logic.SecurityCheck(true, http.HandlerFunc(getUserAccessTokens))).Methods(http.MethodGet)
  52. r.HandleFunc("/api/v1/users/access_token", logic.SecurityCheck(true, http.HandlerFunc(deleteUserAccessTokens))).Methods(http.MethodDelete)
  53. r.HandleFunc("/api/v1/users/logout", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(logout)))).Methods(http.MethodPost)
  54. }
  55. // @Summary Authenticate a user to retrieve an authorization token
  56. // @Router /api/v1/users/{username}/access_token [post]
  57. // @Tags Auth
  58. // @Accept json
  59. // @Param body body models.UserAuthParams true "Authentication parameters"
  60. // @Success 200 {object} models.SuccessResponse
  61. // @Failure 400 {object} models.ErrorResponse
  62. // @Failure 401 {object} models.ErrorResponse
  63. // @Failure 500 {object} models.ErrorResponse
  64. func createUserAccessToken(w http.ResponseWriter, r *http.Request) {
  65. // Auth request consists of Mac Address and Password (from node that is authorizing
  66. // in case of Master, auth is ignored and mac is set to "mastermac"
  67. var req schema.UserAccessToken
  68. err := json.NewDecoder(r.Body).Decode(&req)
  69. if err != nil {
  70. logger.Log(0, "error decoding request body: ",
  71. err.Error())
  72. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
  73. return
  74. }
  75. if req.Name == "" {
  76. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("name is required"), logic.BadReq))
  77. return
  78. }
  79. if req.UserName == "" {
  80. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), logic.BadReq))
  81. return
  82. }
  83. caller, err := logic.GetUser(r.Header.Get("user"))
  84. if err != nil {
  85. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.UnAuthorized))
  86. return
  87. }
  88. user, err := logic.GetUser(req.UserName)
  89. if err != nil {
  90. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.UnAuthorized))
  91. return
  92. }
  93. if caller.UserName != user.UserName && caller.PlatformRoleID != models.SuperAdminRole {
  94. if caller.PlatformRoleID == models.AdminRole {
  95. if user.PlatformRoleID == models.SuperAdminRole || user.PlatformRoleID == models.AdminRole {
  96. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to create token for user "+user.UserName), logic.Forbidden_Msg))
  97. return
  98. }
  99. } else {
  100. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to create token for user "+user.UserName), logic.Forbidden_Msg))
  101. return
  102. }
  103. }
  104. req.ID = uuid.New().String()
  105. req.CreatedBy = r.Header.Get("user")
  106. req.CreatedAt = time.Now()
  107. jwt, err := logic.CreateUserAccessJwtToken(user.UserName, user.PlatformRoleID, req.ExpiresAt, req.ID)
  108. if jwt == "" {
  109. // very unlikely that err is !nil and no jwt returned, but handle it anyways.
  110. logic.ReturnErrorResponse(
  111. w,
  112. r,
  113. logic.FormatError(errors.New("error creating access token "+err.Error()), logic.Internal),
  114. )
  115. return
  116. }
  117. err = req.Create(r.Context())
  118. if err != nil {
  119. logic.ReturnErrorResponse(
  120. w,
  121. r,
  122. logic.FormatError(errors.New("error creating access token "+err.Error()), logic.Internal),
  123. )
  124. return
  125. }
  126. logic.LogEvent(&models.Event{
  127. Action: models.Create,
  128. Source: models.Subject{
  129. ID: caller.UserName,
  130. Name: caller.UserName,
  131. Type: models.UserSub,
  132. },
  133. TriggeredBy: caller.UserName,
  134. Target: models.Subject{
  135. ID: req.ID,
  136. Name: req.Name,
  137. Type: models.UserAccessTokenSub,
  138. Info: req,
  139. },
  140. Origin: models.Dashboard,
  141. })
  142. logic.ReturnSuccessResponseWithJson(w, r, models.SuccessfulUserLoginResponse{
  143. AuthToken: jwt,
  144. UserName: req.UserName,
  145. }, "api access token has generated for user "+req.UserName)
  146. }
  147. // @Summary Authenticate a user to retrieve an authorization token
  148. // @Router /api/v1/users/{username}/access_token [post]
  149. // @Tags Auth
  150. // @Accept json
  151. // @Param body body models.UserAuthParams true "Authentication parameters"
  152. // @Success 200 {object} models.SuccessResponse
  153. // @Failure 400 {object} models.ErrorResponse
  154. // @Failure 401 {object} models.ErrorResponse
  155. // @Failure 500 {object} models.ErrorResponse
  156. func getUserAccessTokens(w http.ResponseWriter, r *http.Request) {
  157. username := r.URL.Query().Get("username")
  158. if username == "" {
  159. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), "badrequest"))
  160. return
  161. }
  162. logic.ReturnSuccessResponseWithJson(w, r, (&schema.UserAccessToken{UserName: username}).ListByUser(r.Context()), "fetched api access tokens for user "+username)
  163. }
  164. // @Summary Authenticate a user to retrieve an authorization token
  165. // @Router /api/v1/users/{username}/access_token [post]
  166. // @Tags Auth
  167. // @Accept json
  168. // @Param body body models.UserAuthParams true "Authentication parameters"
  169. // @Success 200 {object} models.SuccessResponse
  170. // @Failure 400 {object} models.ErrorResponse
  171. // @Failure 401 {object} models.ErrorResponse
  172. // @Failure 500 {object} models.ErrorResponse
  173. func deleteUserAccessTokens(w http.ResponseWriter, r *http.Request) {
  174. id := r.URL.Query().Get("id")
  175. if id == "" {
  176. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("id is required"), "badrequest"))
  177. return
  178. }
  179. a := schema.UserAccessToken{
  180. ID: id,
  181. }
  182. err := a.Get(r.Context())
  183. if err != nil {
  184. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("token does not exist"), "badrequest"))
  185. return
  186. }
  187. caller, err := logic.GetUser(r.Header.Get("user"))
  188. if err != nil {
  189. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized"))
  190. return
  191. }
  192. user, err := logic.GetUser(a.UserName)
  193. if err != nil {
  194. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized"))
  195. return
  196. }
  197. if caller.UserName != user.UserName && caller.PlatformRoleID != models.SuperAdminRole {
  198. if caller.PlatformRoleID == models.AdminRole {
  199. if user.PlatformRoleID == models.SuperAdminRole || user.PlatformRoleID == models.AdminRole {
  200. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to delete token of user "+user.UserName), logic.Forbidden_Msg))
  201. return
  202. }
  203. } else {
  204. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("not enough permissions to delete token of user "+user.UserName), logic.Forbidden_Msg))
  205. return
  206. }
  207. }
  208. err = (&schema.UserAccessToken{ID: id}).Delete(r.Context())
  209. if err != nil {
  210. logic.ReturnErrorResponse(
  211. w,
  212. r,
  213. logic.FormatError(errors.New("error deleting access token "+err.Error()), "internal"),
  214. )
  215. return
  216. }
  217. logic.LogEvent(&models.Event{
  218. Action: models.Delete,
  219. Source: models.Subject{
  220. ID: caller.UserName,
  221. Name: caller.UserName,
  222. Type: models.UserSub,
  223. },
  224. TriggeredBy: caller.UserName,
  225. Target: models.Subject{
  226. ID: a.ID,
  227. Name: a.Name,
  228. Type: models.UserAccessTokenSub,
  229. Info: a,
  230. },
  231. Origin: models.Dashboard,
  232. })
  233. logic.ReturnSuccessResponseWithJson(w, r, nil, "revoked access token")
  234. }
  235. // @Summary Authenticate a user to retrieve an authorization token
  236. // @Router /api/users/adm/authenticate [post]
  237. // @Tags Auth
  238. // @Accept json
  239. // @Param body body models.UserAuthParams true "Authentication parameters"
  240. // @Success 200 {object} models.SuccessResponse
  241. // @Failure 400 {object} models.ErrorResponse
  242. // @Failure 401 {object} models.ErrorResponse
  243. // @Failure 500 {object} models.ErrorResponse
  244. func authenticateUser(response http.ResponseWriter, request *http.Request) {
  245. // Auth request consists of Mac Address and Password (from node that is authorizing
  246. // in case of Master, auth is ignored and mac is set to "mastermac"
  247. var authRequest models.UserAuthParams
  248. var errorResponse = models.ErrorResponse{
  249. Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
  250. }
  251. decoder := json.NewDecoder(request.Body)
  252. decoderErr := decoder.Decode(&authRequest)
  253. defer request.Body.Close()
  254. if decoderErr != nil {
  255. logger.Log(0, "error decoding request body: ",
  256. decoderErr.Error())
  257. logic.ReturnErrorResponse(response, request, errorResponse)
  258. return
  259. }
  260. user, err := logic.GetUser(authRequest.UserName)
  261. if err != nil {
  262. logger.Log(0, authRequest.UserName, "user validation failed: ",
  263. err.Error())
  264. logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized"))
  265. return
  266. }
  267. if logic.IsOauthUser(user) == nil {
  268. logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("user is registered via SSO"), "badrequest"))
  269. return
  270. }
  271. if user.AccountDisabled {
  272. err = errors.New("user account disabled")
  273. logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized"))
  274. return
  275. }
  276. if !user.IsSuperAdmin && !logic.IsBasicAuthEnabled() {
  277. logic.ReturnErrorResponse(
  278. response,
  279. request,
  280. logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
  281. )
  282. return
  283. }
  284. if val := request.Header.Get("From-Ui"); val == "true" {
  285. // request came from UI, if normal user block Login
  286. role, err := logic.GetRole(user.PlatformRoleID)
  287. if err != nil {
  288. logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("access denied to dashboard"), "unauthorized"))
  289. return
  290. }
  291. if role.DenyDashboardAccess {
  292. logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("access denied to dashboard"), "unauthorized"))
  293. return
  294. }
  295. // 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 && logic.GetRacAutoDisable() {
  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 := url.Parse(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.Query().Get("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 totp", 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 totp")
  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. // swagger:route GET /api/v1/users user getUserV1
  673. //
  674. // Get an individual user with role info.
  675. //
  676. // Schemes: https
  677. //
  678. // Security:
  679. // oauth
  680. //
  681. // Responses:
  682. // 200: ReturnUserWithRolesAndGroups
  683. func getUserV1(w http.ResponseWriter, r *http.Request) {
  684. // set header.
  685. w.Header().Set("Content-Type", "application/json")
  686. usernameFetched := r.URL.Query().Get("username")
  687. if usernameFetched == "" {
  688. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username is required"), "badrequest"))
  689. return
  690. }
  691. user, err := logic.GetReturnUser(usernameFetched)
  692. if err != nil {
  693. logger.Log(0, usernameFetched, "failed to fetch user: ", err.Error())
  694. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  695. return
  696. }
  697. userRoleTemplate, err := logic.GetRole(user.PlatformRoleID)
  698. if err != nil {
  699. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  700. return
  701. }
  702. resp := models.ReturnUserWithRolesAndGroups{
  703. ReturnUser: user,
  704. PlatformRole: userRoleTemplate,
  705. UserGroups: map[models.UserGroupID]models.UserGroup{},
  706. }
  707. for gId := range user.UserGroups {
  708. grp, err := logic.GetUserGroup(gId)
  709. if err != nil {
  710. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  711. return
  712. }
  713. resp.UserGroups[gId] = grp
  714. }
  715. logger.Log(2, r.Header.Get("user"), "fetched user", usernameFetched)
  716. logic.ReturnSuccessResponseWithJson(w, r, resp, "fetched user with role info")
  717. }
  718. // swagger:route GET /api/users user getUsers
  719. //
  720. // Get all users.
  721. //
  722. // Schemes: https
  723. //
  724. // Security:
  725. // oauth
  726. //
  727. // Responses:
  728. // 200: userBodyResponse
  729. func getUsers(w http.ResponseWriter, r *http.Request) {
  730. // set header.
  731. w.Header().Set("Content-Type", "application/json")
  732. users, err := logic.GetUsers()
  733. if err != nil {
  734. logger.Log(0, "failed to fetch users: ", err.Error())
  735. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  736. return
  737. }
  738. logic.SortUsers(users[:])
  739. logger.Log(2, r.Header.Get("user"), "fetched users")
  740. json.NewEncoder(w).Encode(users)
  741. }
  742. // @Summary Create a super admin
  743. // @Router /api/users/adm/createsuperadmin [post]
  744. // @Tags Users
  745. // @Param body body models.User true "User details"
  746. // @Success 200 {object} models.User
  747. // @Failure 400 {object} models.ErrorResponse
  748. // @Failure 500 {object} models.ErrorResponse
  749. func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
  750. w.Header().Set("Content-Type", "application/json")
  751. var u models.User
  752. err := json.NewDecoder(r.Body).Decode(&u)
  753. if err != nil {
  754. slog.Error("error decoding request body", "error", err.Error())
  755. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  756. return
  757. }
  758. if !logic.IsBasicAuthEnabled() {
  759. logic.ReturnErrorResponse(
  760. w,
  761. r,
  762. logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
  763. )
  764. return
  765. }
  766. err = logic.CreateSuperAdmin(&u)
  767. if err != nil {
  768. slog.Error("failed to create admin", "error", err.Error())
  769. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  770. return
  771. }
  772. logger.Log(1, u.UserName, "was made a super admin")
  773. json.NewEncoder(w).Encode(logic.ToReturnUser(u))
  774. }
  775. // @Summary Transfer super admin role to another admin user
  776. // @Router /api/users/adm/transfersuperadmin/{username} [post]
  777. // @Tags Users
  778. // @Param username path string true "Username of the user to transfer super admin role"
  779. // @Success 200 {object} models.User
  780. // @Failure 403 {object} models.ErrorResponse
  781. // @Failure 500 {object} models.ErrorResponse
  782. func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
  783. w.Header().Set("Content-Type", "application/json")
  784. caller, err := logic.GetUser(r.Header.Get("user"))
  785. if err != nil {
  786. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  787. }
  788. if caller.PlatformRoleID != models.SuperAdminRole {
  789. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only superadmin can assign the superadmin role to another user"), "forbidden"))
  790. return
  791. }
  792. var params = mux.Vars(r)
  793. username := params["username"]
  794. u, err := logic.GetUser(username)
  795. if err != nil {
  796. slog.Error("error getting user", "user", u.UserName, "error", err.Error())
  797. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  798. return
  799. }
  800. if u.PlatformRoleID != models.AdminRole {
  801. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only admins can be promoted to superadmin role"), "forbidden"))
  802. return
  803. }
  804. if !logic.IsBasicAuthEnabled() {
  805. logic.ReturnErrorResponse(
  806. w,
  807. r,
  808. logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"),
  809. )
  810. return
  811. }
  812. u.PlatformRoleID = models.SuperAdminRole
  813. err = logic.UpsertUser(*u)
  814. if err != nil {
  815. slog.Error("error updating user to superadmin: ", "user", u.UserName, "error", err.Error())
  816. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  817. return
  818. }
  819. caller.PlatformRoleID = models.AdminRole
  820. err = logic.UpsertUser(*caller)
  821. if err != nil {
  822. slog.Error("error demoting user to admin: ", "user", caller.UserName, "error", err.Error())
  823. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  824. return
  825. }
  826. slog.Info("user was made a super admin", "user", u.UserName)
  827. json.NewEncoder(w).Encode(logic.ToReturnUser(*u))
  828. }
  829. // @Summary Create a user
  830. // @Router /api/users/{username} [post]
  831. // @Tags Users
  832. // @Param username path string true "Username of the user to create"
  833. // @Param body body models.User true "User details"
  834. // @Success 200 {object} models.User
  835. // @Failure 400 {object} models.ErrorResponse
  836. // @Failure 403 {object} models.ErrorResponse
  837. // @Failure 500 {object} models.ErrorResponse
  838. func createUser(w http.ResponseWriter, r *http.Request) {
  839. w.Header().Set("Content-Type", "application/json")
  840. caller, err := logic.GetUser(r.Header.Get("user"))
  841. if err != nil {
  842. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  843. return
  844. }
  845. var user models.User
  846. err = json.NewDecoder(r.Body).Decode(&user)
  847. if err != nil {
  848. logger.Log(0, user.UserName, "error decoding request body: ",
  849. err.Error())
  850. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  851. return
  852. }
  853. if !servercfg.IsPro {
  854. user.PlatformRoleID = models.AdminRole
  855. }
  856. if user.UserName == logic.MasterUser {
  857. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("username not allowed"), "badrequest"))
  858. return
  859. }
  860. if user.PlatformRoleID == "" {
  861. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("platform role is missing"), "badrequest"))
  862. return
  863. }
  864. userRole, err := logic.GetRole(user.PlatformRoleID)
  865. if err != nil {
  866. err = errors.New("error fetching role " + user.PlatformRoleID.String() + " " + err.Error())
  867. slog.Error("error creating new user: ", "user", user.UserName, "error", err)
  868. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  869. return
  870. }
  871. if userRole.ID == models.SuperAdminRole {
  872. err = errors.New("additional superadmins cannot be created")
  873. slog.Error("error creating new user: ", "user", user.UserName, "error", err)
  874. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  875. return
  876. }
  877. if caller.PlatformRoleID != models.SuperAdminRole && user.PlatformRoleID == models.AdminRole {
  878. err = errors.New("only superadmin can create admin users")
  879. slog.Error("error creating new user: ", "user", user.UserName, "error", err)
  880. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  881. return
  882. }
  883. if !servercfg.IsPro && user.PlatformRoleID != models.AdminRole {
  884. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("non-admins users can only be created on Pro version"), "forbidden"))
  885. return
  886. }
  887. err = logic.CreateUser(&user)
  888. if err != nil {
  889. slog.Error("error creating new user: ", "user", user.UserName, "error", err.Error())
  890. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  891. return
  892. }
  893. logic.LogEvent(&models.Event{
  894. Action: models.Create,
  895. Source: models.Subject{
  896. ID: caller.UserName,
  897. Name: caller.UserName,
  898. Type: models.UserSub,
  899. },
  900. TriggeredBy: caller.UserName,
  901. Target: models.Subject{
  902. ID: user.UserName,
  903. Name: user.UserName,
  904. Type: models.UserSub,
  905. Info: user,
  906. },
  907. Origin: models.Dashboard,
  908. })
  909. logic.DeleteUserInvite(user.UserName)
  910. logic.DeletePendingUser(user.UserName)
  911. go mq.PublishPeerUpdate(false)
  912. slog.Info("user was created", "username", user.UserName)
  913. json.NewEncoder(w).Encode(logic.ToReturnUser(user))
  914. }
  915. // @Summary Update a user
  916. // @Router /api/users/{username} [put]
  917. // @Tags Users
  918. // @Param username path string true "Username of the user to update"
  919. // @Param body body models.User true "User details"
  920. // @Success 200 {object} models.User
  921. // @Failure 400 {object} models.ErrorResponse
  922. // @Failure 403 {object} models.ErrorResponse
  923. // @Failure 500 {object} models.ErrorResponse
  924. func updateUser(w http.ResponseWriter, r *http.Request) {
  925. w.Header().Set("Content-Type", "application/json")
  926. var params = mux.Vars(r)
  927. // start here
  928. var caller *models.User
  929. var err error
  930. var ismaster bool
  931. if r.Header.Get("user") == logic.MasterUser {
  932. ismaster = true
  933. } else {
  934. caller, err = logic.GetUser(r.Header.Get("user"))
  935. if err != nil {
  936. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  937. }
  938. }
  939. username := params["username"]
  940. user, err := logic.GetUser(username)
  941. if err != nil {
  942. logger.Log(0, username,
  943. "failed to update user info: ", err.Error())
  944. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  945. return
  946. }
  947. var userchange models.User
  948. // we decode our body request params
  949. err = json.NewDecoder(r.Body).Decode(&userchange)
  950. if err != nil {
  951. slog.Error("failed to decode body", "error ", err.Error())
  952. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  953. return
  954. }
  955. if user.UserName != userchange.UserName {
  956. logic.ReturnErrorResponse(
  957. w,
  958. r,
  959. logic.FormatError(
  960. errors.New("user in param and request body not matching"),
  961. "badrequest",
  962. ),
  963. )
  964. return
  965. }
  966. selfUpdate := false
  967. if !ismaster && caller.UserName == user.UserName {
  968. selfUpdate = true
  969. }
  970. if !ismaster && !selfUpdate {
  971. if caller.PlatformRoleID == models.AdminRole && user.PlatformRoleID == models.SuperAdminRole {
  972. slog.Error("non-superadmin user", "caller", caller.UserName, "attempted to update superadmin user", username)
  973. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
  974. return
  975. }
  976. if caller.PlatformRoleID != models.AdminRole && caller.PlatformRoleID != models.SuperAdminRole {
  977. slog.Error("operation not allowed", "caller", caller.UserName, "attempted to update user", username)
  978. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
  979. return
  980. }
  981. if caller.PlatformRoleID == models.AdminRole && user.PlatformRoleID == models.AdminRole {
  982. slog.Error("an admin user does not have permissions to update another admin user", "caller", caller.UserName, "attempted to update admin user", username)
  983. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("an admin user does not have permissions to update another admin user"), "forbidden"))
  984. return
  985. }
  986. if caller.PlatformRoleID == models.AdminRole && userchange.PlatformRoleID == models.AdminRole {
  987. err = errors.New("an admin user does not have permissions to assign the admin role to another user")
  988. slog.Error(
  989. "failed to update user",
  990. "caller",
  991. caller.UserName,
  992. "attempted to update user",
  993. username,
  994. "error",
  995. err,
  996. )
  997. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  998. return
  999. }
  1000. }
  1001. if !ismaster && selfUpdate {
  1002. if user.PlatformRoleID != userchange.PlatformRoleID {
  1003. slog.Error("user cannot change his own role", "caller", caller.UserName, "attempted to update user role", username)
  1004. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"))
  1005. return
  1006. }
  1007. if servercfg.IsPro {
  1008. // user cannot update his own roles and groups
  1009. if len(user.NetworkRoles) != len(userchange.NetworkRoles) || !reflect.DeepEqual(user.NetworkRoles, userchange.NetworkRoles) {
  1010. err = errors.New("user cannot update self update their network roles")
  1011. slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)
  1012. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  1013. return
  1014. }
  1015. // user cannot update his own roles and groups
  1016. if len(user.UserGroups) != len(userchange.UserGroups) || !reflect.DeepEqual(user.UserGroups, userchange.UserGroups) {
  1017. err = errors.New("user cannot update self update their groups")
  1018. slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)
  1019. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  1020. return
  1021. }
  1022. }
  1023. }
  1024. if ismaster {
  1025. if user.PlatformRoleID != models.SuperAdminRole && userchange.PlatformRoleID == models.SuperAdminRole {
  1026. slog.Error("operation not allowed", "caller", logic.MasterUser, "attempted to update user role to superadmin", username)
  1027. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("attempted to update user role to superadmin"), "forbidden"))
  1028. return
  1029. }
  1030. }
  1031. if logic.IsOauthUser(user) == nil && userchange.Password != "" {
  1032. err := fmt.Errorf("cannot update user's password for an oauth user %s", username)
  1033. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  1034. return
  1035. }
  1036. logic.AddGlobalNetRolesToAdmins(&userchange)
  1037. if userchange.PlatformRoleID != user.PlatformRoleID || !logic.CompareMaps(user.UserGroups, userchange.UserGroups) {
  1038. (&schema.UserAccessToken{UserName: user.UserName}).DeleteAllUserTokens(r.Context())
  1039. }
  1040. oldUser := *user
  1041. e := models.Event{
  1042. Action: models.Update,
  1043. Source: models.Subject{
  1044. ID: caller.UserName,
  1045. Name: caller.UserName,
  1046. Type: models.UserSub,
  1047. },
  1048. TriggeredBy: caller.UserName,
  1049. Target: models.Subject{
  1050. ID: user.UserName,
  1051. Name: user.UserName,
  1052. Type: models.UserSub,
  1053. },
  1054. Diff: models.Diff{
  1055. Old: oldUser,
  1056. New: userchange,
  1057. },
  1058. Origin: models.Dashboard,
  1059. }
  1060. user, err = logic.UpdateUser(&userchange, user)
  1061. if err != nil {
  1062. logger.Log(0, username,
  1063. "failed to update user info: ", err.Error())
  1064. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  1065. return
  1066. }
  1067. logic.LogEvent(&e)
  1068. go mq.PublishPeerUpdate(false)
  1069. logger.Log(1, username, "was updated")
  1070. json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
  1071. }
  1072. // @Summary Delete a user
  1073. // @Router /api/users/{username} [delete]
  1074. // @Tags Users
  1075. // @Param username path string true "Username of the user to delete"
  1076. // @Success 200 {string} string
  1077. // @Failure 500 {object} models.ErrorResponse
  1078. func deleteUser(w http.ResponseWriter, r *http.Request) {
  1079. // Set header
  1080. w.Header().Set("Content-Type", "application/json")
  1081. // get params
  1082. var params = mux.Vars(r)
  1083. caller, err := logic.GetUser(r.Header.Get("user"))
  1084. if err != nil {
  1085. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1086. }
  1087. callerUserRole, err := logic.GetRole(caller.PlatformRoleID)
  1088. if err != nil {
  1089. slog.Error("failed to get role ", "role", callerUserRole.ID, "error", err)
  1090. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1091. return
  1092. }
  1093. username := params["username"]
  1094. user, err := logic.GetUser(username)
  1095. if err != nil {
  1096. logger.Log(0, username,
  1097. "failed to update user info: ", err.Error())
  1098. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1099. return
  1100. }
  1101. userRole, err := logic.GetRole(user.PlatformRoleID)
  1102. if err != nil {
  1103. slog.Error("failed to get role ", "role", userRole.ID, "error", err)
  1104. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1105. return
  1106. }
  1107. if userRole.ID == models.SuperAdminRole {
  1108. slog.Error(
  1109. "failed to delete user: ", "user", username, "error", "superadmin cannot be deleted")
  1110. logic.ReturnErrorResponse(
  1111. w,
  1112. r,
  1113. logic.FormatError(fmt.Errorf("superadmin cannot be deleted"), "internal"),
  1114. )
  1115. return
  1116. }
  1117. if callerUserRole.ID != models.SuperAdminRole {
  1118. if callerUserRole.ID == models.AdminRole && userRole.ID == models.AdminRole {
  1119. slog.Error(
  1120. "failed to delete user: ",
  1121. "user",
  1122. username,
  1123. "error",
  1124. "admin cannot delete another admin user, including oneself",
  1125. )
  1126. logic.ReturnErrorResponse(
  1127. w,
  1128. r,
  1129. logic.FormatError(
  1130. fmt.Errorf("admin cannot delete another admin user, including oneself"),
  1131. "internal",
  1132. ),
  1133. )
  1134. return
  1135. }
  1136. }
  1137. err = logic.DeleteUser(username)
  1138. if err != nil {
  1139. logger.Log(0, username,
  1140. "failed to delete user: ", err.Error())
  1141. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  1142. return
  1143. }
  1144. logic.LogEvent(&models.Event{
  1145. Action: models.Delete,
  1146. Source: models.Subject{
  1147. ID: caller.UserName,
  1148. Name: caller.UserName,
  1149. Type: models.UserSub,
  1150. },
  1151. TriggeredBy: caller.UserName,
  1152. Target: models.Subject{
  1153. ID: user.UserName,
  1154. Name: user.UserName,
  1155. Type: models.UserSub,
  1156. },
  1157. Origin: models.Dashboard,
  1158. })
  1159. // check and delete extclient with this ownerID
  1160. go func() {
  1161. extclients, err := logic.GetAllExtClients()
  1162. if err != nil {
  1163. slog.Error("failed to get extclients", "error", err)
  1164. return
  1165. }
  1166. for _, extclient := range extclients {
  1167. if extclient.OwnerID == user.UserName {
  1168. err = logic.DeleteExtClientAndCleanup(extclient)
  1169. if err != nil {
  1170. slog.Error("failed to delete extclient",
  1171. "id", extclient.ClientID, "owner", username, "error", err)
  1172. } else {
  1173. if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {
  1174. slog.Error("error setting ext peers: " + err.Error())
  1175. }
  1176. }
  1177. }
  1178. }
  1179. mq.PublishPeerUpdate(false)
  1180. if servercfg.IsDNSMode() {
  1181. logic.SetDNS()
  1182. }
  1183. }()
  1184. logger.Log(1, username, "was deleted")
  1185. json.NewEncoder(w).Encode(params["username"] + " deleted.")
  1186. }
  1187. // Called when vpn client dials in to start the auth flow and first stage is to get register URL itself
  1188. func socketHandler(w http.ResponseWriter, r *http.Request) {
  1189. // Upgrade our raw HTTP connection to a websocket based one
  1190. conn, err := upgrader.Upgrade(w, r, nil)
  1191. if err != nil {
  1192. logger.Log(0, "error during connection upgrade for node sign-in:", err.Error())
  1193. return
  1194. }
  1195. if conn == nil {
  1196. logger.Log(0, "failed to establish web-socket connection during node sign-in")
  1197. return
  1198. }
  1199. // Start handling the session
  1200. go auth.SessionHandler(conn)
  1201. }
  1202. // @Summary lists all user roles.
  1203. // @Router /api/v1/user/roles [get]
  1204. // @Tags Users
  1205. // @Param role_id query string true "roleid required to get the role details"
  1206. // @Success 200 {object} []models.UserRolePermissionTemplate
  1207. // @Failure 500 {object} models.ErrorResponse
  1208. func listRoles(w http.ResponseWriter, r *http.Request) {
  1209. var roles []models.UserRolePermissionTemplate
  1210. var err error
  1211. roles, err = logic.ListPlatformRoles()
  1212. if err != nil {
  1213. logic.ReturnErrorResponse(w, r, models.ErrorResponse{
  1214. Code: http.StatusInternalServerError,
  1215. Message: err.Error(),
  1216. })
  1217. return
  1218. }
  1219. logic.ReturnSuccessResponseWithJson(w, r, roles, "successfully fetched user roles permission templates")
  1220. }
  1221. // swagger:route POST /api/v1/user/logout user logout
  1222. //
  1223. // LogOut user.
  1224. //
  1225. // Schemes: https
  1226. //
  1227. // Security:
  1228. // oauth
  1229. //
  1230. // Responses:
  1231. // 200: userBodyResponse
  1232. func logout(w http.ResponseWriter, r *http.Request) {
  1233. // set header.
  1234. w.Header().Set("Content-Type", "application/json")
  1235. userName := r.URL.Query().Get("username")
  1236. user, err := logic.GetUser(userName)
  1237. if err != nil {
  1238. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
  1239. return
  1240. }
  1241. var target models.SubjectType
  1242. if val := r.Header.Get("From-Ui"); val == "true" {
  1243. target = models.DashboardSub
  1244. } else {
  1245. target = models.ClientAppSub
  1246. }
  1247. if target != "" {
  1248. logic.LogEvent(&models.Event{
  1249. Action: models.LogOut,
  1250. Source: models.Subject{
  1251. ID: user.UserName,
  1252. Name: user.UserName,
  1253. Type: models.UserSub,
  1254. },
  1255. TriggeredBy: user.UserName,
  1256. Target: models.Subject{
  1257. ID: target.String(),
  1258. Name: target.String(),
  1259. Type: target,
  1260. },
  1261. Origin: models.Origin(target),
  1262. })
  1263. }
  1264. logic.ReturnSuccessResponse(w, r, "user logged out")
  1265. }