user.go 46 KB

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