2
0

user.go 38 KB

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