user.go 55 KB

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