user.go 46 KB

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