2015-01-19 11:01:04 -06:00
package api
import (
2021-09-27 09:43:16 -05:00
"context"
2020-11-19 06:34:28 -06:00
"errors"
2021-12-22 11:46:33 -06:00
"fmt"
2021-11-29 03:18:01 -06:00
"net/http"
2022-01-14 10:55:57 -06:00
"strconv"
2020-11-19 06:34:28 -06:00
2017-08-18 01:17:35 -05:00
"github.com/grafana/grafana/pkg/api/dtos"
2021-01-15 07:43:20 -06:00
"github.com/grafana/grafana/pkg/api/response"
2022-08-17 09:32:02 -05:00
"github.com/grafana/grafana/pkg/services/accesscontrol"
2023-01-27 01:50:36 -06:00
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
2023-07-25 07:27:02 -05:00
"github.com/grafana/grafana/pkg/services/featuremgmt"
2022-11-29 08:20:28 -06:00
"github.com/grafana/grafana/pkg/services/login"
2022-09-23 04:59:07 -05:00
"github.com/grafana/grafana/pkg/services/org"
2023-09-28 03:16:18 -05:00
"github.com/grafana/grafana/pkg/services/searchusers/sortopts"
2022-08-04 06:22:43 -05:00
"github.com/grafana/grafana/pkg/services/user"
2020-09-14 01:58:23 -05:00
"github.com/grafana/grafana/pkg/util"
2021-11-29 03:18:01 -06:00
"github.com/grafana/grafana/pkg/web"
2015-01-19 11:01:04 -06:00
)
2022-07-27 08:54:37 -05:00
// swagger:route POST /org/users org addOrgUserToCurrentOrg
//
2022-09-12 02:40:35 -05:00
// Add a new user to the current organization.
2022-07-27 08:54:37 -05:00
//
// Adds a global user to the current organization.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `org.users:add` with scope `users:*`.
//
// Responses:
// 200: okResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) AddOrgUserToCurrentOrg ( c * contextmodel . ReqContext ) response . Response {
2022-09-23 04:59:07 -05:00
cmd := org . AddOrgUserCommand { }
2021-11-29 03:18:01 -06:00
if err := web . Bind ( c . Req , & cmd ) ; err != nil {
return response . Error ( http . StatusBadRequest , "bad request data" , err )
}
2023-08-28 03:42:24 -05:00
cmd . OrgID = c . SignedInUser . GetOrgID ( )
2022-06-27 11:40:12 -05:00
return hs . addOrgUserHelper ( c , cmd )
2015-05-19 03:16:32 -05:00
}
2022-07-27 08:54:37 -05:00
// swagger:route POST /orgs/{org_id}/users orgs addOrgUser
//
2022-09-12 02:40:35 -05:00
// Add a new user to the current organization.
2022-07-27 08:54:37 -05:00
//
// Adds a global user to the current organization.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `org.users:add` with scope `users:*`.
//
// Responses:
// 200: okResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) AddOrgUser ( c * contextmodel . ReqContext ) response . Response {
2022-09-23 04:59:07 -05:00
cmd := org . AddOrgUserCommand { }
2021-11-29 03:18:01 -06:00
if err := web . Bind ( c . Req , & cmd ) ; err != nil {
return response . Error ( http . StatusBadRequest , "bad request data" , err )
}
2022-01-14 10:55:57 -06:00
var err error
2022-09-23 04:59:07 -05:00
cmd . OrgID , err = strconv . ParseInt ( web . Params ( c . Req ) [ ":orgId" ] , 10 , 64 )
2022-01-14 10:55:57 -06:00
if err != nil {
return response . Error ( http . StatusBadRequest , "orgId is invalid" , err )
}
2022-06-27 11:40:12 -05:00
return hs . addOrgUserHelper ( c , cmd )
2015-05-19 03:16:32 -05:00
}
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) addOrgUserHelper ( c * contextmodel . ReqContext , cmd org . AddOrgUserCommand ) response . Response {
2015-01-19 11:01:04 -06:00
if ! cmd . Role . IsValid ( ) {
2023-08-28 03:42:24 -05:00
return response . Error ( http . StatusBadRequest , "Invalid role specified" , nil )
2015-01-19 11:01:04 -06:00
}
2023-08-28 03:42:24 -05:00
if ! c . SignedInUser . GetOrgRole ( ) . Includes ( cmd . Role ) && ! c . SignedInUser . GetIsGrafanaAdmin ( ) {
2022-06-27 11:40:12 -05:00
return response . Error ( http . StatusForbidden , "Cannot assign a role higher than user's role" , nil )
}
2015-01-19 11:01:04 -06:00
2022-08-04 06:22:43 -05:00
userQuery := user . GetUserByLoginQuery { LoginOrEmail : cmd . LoginOrEmail }
userToAdd , err := hs . userService . GetByLogin ( c . Req . Context ( ) , & userQuery )
2015-01-19 11:01:04 -06:00
if err != nil {
2023-08-28 03:42:24 -05:00
return response . Error ( http . StatusNotFound , "User not found" , nil )
2015-01-19 11:01:04 -06:00
}
2022-09-23 04:59:07 -05:00
cmd . UserID = userToAdd . ID
2015-01-19 11:01:04 -06:00
2022-09-23 04:59:07 -05:00
if err := hs . orgService . AddOrgUser ( c . Req . Context ( ) , & cmd ) ; err != nil {
2023-01-09 07:39:53 -06:00
if errors . Is ( err , org . ErrOrgUserAlreadyAdded ) {
2023-08-28 03:42:24 -05:00
return response . JSON ( http . StatusConflict , util . DynMap {
2020-09-14 01:58:23 -05:00
"message" : "User is already member of this organization" ,
2022-09-23 04:59:07 -05:00
"userId" : cmd . UserID ,
2020-09-14 01:58:23 -05:00
} )
2016-11-23 07:38:44 -06:00
}
2023-08-28 03:42:24 -05:00
return response . Error ( http . StatusInternalServerError , "Could not add user to organization" , err )
2015-01-19 11:01:04 -06:00
}
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , util . DynMap {
2020-09-14 01:58:23 -05:00
"message" : "User added to organization" ,
2022-09-23 04:59:07 -05:00
"userId" : cmd . UserID ,
2020-09-14 01:58:23 -05:00
} )
2015-05-19 03:16:32 -05:00
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /org/users org getOrgUsersForCurrentOrg
//
// Get all users within the current organization.
//
// Returns all org users within the current organization. Accessible to users with org admin role.
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `org.users:read` with scope `users:*`.
//
// Responses:
// 200: getOrgUsersForCurrentOrgResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) GetOrgUsersForCurrentOrg ( c * contextmodel . ReqContext ) response . Response {
2023-01-09 02:54:33 -06:00
result , err := hs . searchOrgUsersHelper ( c , & org . SearchOrgUsersQuery {
2023-08-28 03:42:24 -05:00
OrgID : c . SignedInUser . GetOrgID ( ) ,
2020-11-24 05:10:32 -06:00
Query : c . Query ( "query" ) ,
Limit : c . QueryInt ( "limit" ) ,
2022-01-13 07:40:32 -06:00
User : c . SignedInUser ,
2023-01-09 02:54:33 -06:00
} )
2020-11-24 05:10:32 -06:00
2019-08-12 13:03:48 -05:00
if err != nil {
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to get users for current organization" , err )
2019-08-12 13:03:48 -05:00
}
2023-01-09 02:54:33 -06:00
return response . JSON ( http . StatusOK , result . OrgUsers )
2019-08-12 13:03:48 -05:00
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /org/users/lookup org getOrgUsersForCurrentOrgLookup
//
// Get all users within the current organization (lookup)
//
// Returns all org users within the current organization, but with less detailed information.
// Accessible to users with org admin role, admin in any folder or admin of any team.
// Mainly used by Grafana UI for providing list of users when adding team members and when editing folder/dashboard permissions.
//
// Responses:
// 200: getOrgUsersForCurrentOrgLookupResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) GetOrgUsersForCurrentOrgLookup ( c * contextmodel . ReqContext ) response . Response {
2023-01-09 02:54:33 -06:00
orgUsersResult , err := hs . searchOrgUsersHelper ( c , & org . SearchOrgUsersQuery {
2023-08-28 03:42:24 -05:00
OrgID : c . SignedInUser . GetOrgID ( ) ,
2022-05-25 13:40:41 -05:00
Query : c . Query ( "query" ) ,
Limit : c . QueryInt ( "limit" ) ,
User : c . SignedInUser ,
DontEnforceAccessControl : ! hs . License . FeatureEnabled ( "accesscontrol.enforcement" ) ,
2023-01-09 02:54:33 -06:00
} )
2020-11-24 05:10:32 -06:00
2019-08-12 13:03:48 -05:00
if err != nil {
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to get users for current organization" , err )
2019-08-12 13:03:48 -05:00
}
result := make ( [ ] * dtos . UserLookupDTO , 0 )
2023-01-09 02:54:33 -06:00
for _ , u := range orgUsersResult . OrgUsers {
2019-08-12 13:03:48 -05:00
result = append ( result , & dtos . UserLookupDTO {
2022-09-26 03:27:38 -05:00
UserID : u . UserID ,
2019-08-12 13:03:48 -05:00
Login : u . Login ,
2022-09-26 03:27:38 -05:00
AvatarURL : u . AvatarURL ,
2019-08-12 13:03:48 -05:00
} )
}
2022-04-15 07:01:58 -05:00
return response . JSON ( http . StatusOK , result )
2019-08-12 13:03:48 -05:00
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /orgs/{org_id}/users orgs getOrgUsers
//
// Get Users in Organization.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `org.users:read` with scope `users:*`.
//
// Security:
// - basic:
//
// Responses:
// 200: getOrgUsersResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) GetOrgUsers ( c * contextmodel . ReqContext ) response . Response {
2022-01-14 10:55:57 -06:00
orgId , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":orgId" ] , 10 , 64 )
if err != nil {
return response . Error ( http . StatusBadRequest , "orgId is invalid" , err )
}
2023-01-09 02:54:33 -06:00
result , err := hs . searchOrgUsersHelper ( c , & org . SearchOrgUsersQuery {
2022-09-26 03:27:38 -05:00
OrgID : orgId ,
2020-11-24 05:10:32 -06:00
Query : "" ,
Limit : 0 ,
2022-01-13 07:40:32 -06:00
User : c . SignedInUser ,
2023-01-09 02:54:33 -06:00
} )
2020-11-24 05:10:32 -06:00
2019-08-12 13:03:48 -05:00
if err != nil {
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to get users for organization" , err )
2019-08-12 13:03:48 -05:00
}
2023-01-09 02:54:33 -06:00
return response . JSON ( http . StatusOK , result . OrgUsers )
2015-01-19 11:01:04 -06:00
}
2023-01-09 02:54:33 -06:00
// swagger:route GET /orgs/{org_id}/users/search orgs searchOrgUsers
//
// Search Users in Organization.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `org.users:read` with scope `users:*`.
//
// Security:
// - basic:
//
// Responses:
// 200: searchOrgUsersResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) SearchOrgUsers ( c * contextmodel . ReqContext ) response . Response {
2023-01-09 02:54:33 -06:00
orgID , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":orgId" ] , 10 , 64 )
2022-09-26 03:27:38 -05:00
if err != nil {
2023-01-09 02:54:33 -06:00
return response . Error ( http . StatusBadRequest , "orgId is invalid" , err )
2015-01-19 11:01:04 -06:00
}
2023-01-09 02:54:33 -06:00
perPage := c . QueryInt ( "perpage" )
if perPage <= 0 {
perPage = 1000
}
page := c . QueryInt ( "page" )
2020-11-24 05:10:32 -06:00
2023-01-09 02:54:33 -06:00
if page < 1 {
page = 1
2022-01-05 02:59:17 -06:00
}
2021-12-22 11:46:33 -06:00
2023-09-28 03:16:18 -05:00
sortOpts , err := sortopts . ParseSortQueryParam ( c . Query ( "sort" ) )
if err != nil {
return response . Err ( err )
}
2023-01-09 02:54:33 -06:00
result , err := hs . searchOrgUsersHelper ( c , & org . SearchOrgUsersQuery {
2023-09-28 03:16:18 -05:00
OrgID : orgID ,
Query : c . Query ( "query" ) ,
Page : page ,
Limit : perPage ,
User : c . SignedInUser ,
SortOpts : sortOpts ,
2022-11-29 08:20:28 -06:00
} )
if err != nil {
2023-01-09 02:54:33 -06:00
return response . Error ( 500 , "Failed to get users for organization" , err )
2017-08-18 01:17:35 -05:00
}
2023-01-09 02:54:33 -06:00
return response . JSON ( http . StatusOK , result )
2015-01-19 11:01:04 -06:00
}
2021-05-12 07:10:35 -05:00
// SearchOrgUsersWithPaging is an HTTP handler to search for org users with paging.
// GET /api/org/users/search
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) SearchOrgUsersWithPaging ( c * contextmodel . ReqContext ) response . Response {
2021-05-12 07:10:35 -05:00
perPage := c . QueryInt ( "perpage" )
if perPage <= 0 {
perPage = 1000
}
page := c . QueryInt ( "page" )
if page < 1 {
page = 1
}
2023-09-28 03:16:18 -05:00
sortOpts , err := sortopts . ParseSortQueryParam ( c . Query ( "sort" ) )
if err != nil {
return response . Err ( err )
}
2022-09-26 11:53:17 -05:00
query := & org . SearchOrgUsersQuery {
2023-09-28 03:16:18 -05:00
OrgID : c . SignedInUser . GetOrgID ( ) ,
Query : c . Query ( "query" ) ,
Page : page ,
Limit : perPage ,
User : c . SignedInUser ,
SortOpts : sortOpts ,
2021-05-12 07:10:35 -05:00
}
2023-01-09 02:54:33 -06:00
result , err := hs . searchOrgUsersHelper ( c , query )
2022-09-26 11:53:17 -05:00
if err != nil {
2021-05-12 07:10:35 -05:00
return response . Error ( 500 , "Failed to get users for current organization" , err )
}
2023-01-09 02:54:33 -06:00
return response . JSON ( http . StatusOK , result )
}
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) searchOrgUsersHelper ( c * contextmodel . ReqContext , query * org . SearchOrgUsersQuery ) ( * org . SearchOrgUsersQueryResult , error ) {
2023-01-09 02:54:33 -06:00
result , err := hs . orgService . SearchOrgUsers ( c . Req . Context ( ) , query )
if err != nil {
return nil , err
}
2022-09-26 11:53:17 -05:00
filteredUsers := make ( [ ] * org . OrgUserDTO , 0 , len ( result . OrgUsers ) )
2023-01-09 02:54:33 -06:00
userIDs := map [ string ] bool { }
authLabelsUserIDs := make ( [ ] int64 , 0 , len ( result . OrgUsers ) )
2022-09-26 11:53:17 -05:00
for _ , user := range result . OrgUsers {
2021-05-12 07:10:35 -05:00
if dtos . IsHiddenUser ( user . Login , c . SignedInUser , hs . Cfg ) {
continue
}
2022-09-26 11:53:17 -05:00
user . AvatarURL = dtos . GetGravatarUrl ( user . Email )
2021-05-12 07:10:35 -05:00
2023-01-09 02:54:33 -06:00
userIDs [ fmt . Sprint ( user . UserID ) ] = true
authLabelsUserIDs = append ( authLabelsUserIDs , user . UserID )
2023-03-22 12:41:59 -05:00
2021-05-12 07:10:35 -05:00
filteredUsers = append ( filteredUsers , user )
}
2023-01-27 12:36:54 -06:00
modules , err := hs . authInfoService . GetUserLabels ( c . Req . Context ( ) , login . GetUserLabelsQuery {
2023-01-09 02:54:33 -06:00
UserIDs : authLabelsUserIDs ,
} )
2021-05-12 07:10:35 -05:00
2023-01-09 02:54:33 -06:00
if err != nil {
hs . log . Warn ( "failed to retrieve users IDP label" , err )
}
// Get accesscontrol metadata and IPD labels for users in the target org
2023-08-18 05:42:18 -05:00
accessControlMetadata := map [ string ] accesscontrol . Metadata { }
if c . QueryBool ( "accesscontrol" ) && c . SignedInUser . Permissions != nil {
// TODO https://github.com/grafana/grafana-authnz-team/issues/268 - user access control service for fetching permissions from another organization
permissions , ok := c . SignedInUser . Permissions [ query . OrgID ]
if ok {
accessControlMetadata = accesscontrol . GetResourcesMetadata ( c . Req . Context ( ) , permissions , "users:id:" , userIDs )
}
}
2023-01-09 02:54:33 -06:00
for i := range filteredUsers {
filteredUsers [ i ] . AccessControl = accessControlMetadata [ fmt . Sprint ( filteredUsers [ i ] . UserID ) ]
if module , ok := modules [ filteredUsers [ i ] . UserID ] ; ok {
filteredUsers [ i ] . AuthLabels = [ ] string { login . GetAuthProviderLabel ( module ) }
2023-03-22 12:41:59 -05:00
filteredUsers [ i ] . IsExternallySynced = login . IsExternallySynced ( hs . Cfg , module )
2023-01-09 02:54:33 -06:00
}
}
result . OrgUsers = filteredUsers
result . Page = query . Page
result . PerPage = query . Limit
return result , nil
2021-05-12 07:10:35 -05:00
}
2022-07-27 08:54:37 -05:00
// swagger:route PATCH /org/users/{user_id} org updateOrgUserForCurrentOrg
//
2022-09-12 02:40:35 -05:00
// Updates the given user.
2022-07-27 08:54:37 -05:00
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `org.users.role:update` with scope `users:*`.
//
// Responses:
// 200: okResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) UpdateOrgUserForCurrentOrg ( c * contextmodel . ReqContext ) response . Response {
2022-09-26 03:27:38 -05:00
cmd := org . UpdateOrgUserCommand { }
2021-11-29 03:18:01 -06:00
if err := web . Bind ( c . Req , & cmd ) ; err != nil {
return response . Error ( http . StatusBadRequest , "bad request data" , err )
}
2023-08-28 03:42:24 -05:00
cmd . OrgID = c . SignedInUser . GetOrgID ( )
2022-01-14 10:55:57 -06:00
var err error
2022-09-26 03:27:38 -05:00
cmd . UserID , err = strconv . ParseInt ( web . Params ( c . Req ) [ ":userId" ] , 10 , 64 )
2022-01-14 10:55:57 -06:00
if err != nil {
return response . Error ( http . StatusBadRequest , "userId is invalid" , err )
}
2022-06-27 11:40:12 -05:00
return hs . updateOrgUserHelper ( c , cmd )
2015-05-19 03:16:32 -05:00
}
2022-07-27 08:54:37 -05:00
// swagger:route PATCH /orgs/{org_id}/users/{user_id} orgs updateOrgUser
//
// Update Users in Organization.
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `org.users.role:update` with scope `users:*`.
//
// Responses:
// 200: okResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) UpdateOrgUser ( c * contextmodel . ReqContext ) response . Response {
2022-09-26 03:27:38 -05:00
cmd := org . UpdateOrgUserCommand { }
2022-01-14 10:55:57 -06:00
var err error
2021-11-29 03:18:01 -06:00
if err := web . Bind ( c . Req , & cmd ) ; err != nil {
return response . Error ( http . StatusBadRequest , "bad request data" , err )
}
2022-09-26 03:27:38 -05:00
cmd . OrgID , err = strconv . ParseInt ( web . Params ( c . Req ) [ ":orgId" ] , 10 , 64 )
2022-01-14 10:55:57 -06:00
if err != nil {
return response . Error ( http . StatusBadRequest , "orgId is invalid" , err )
}
2022-09-26 03:27:38 -05:00
cmd . UserID , err = strconv . ParseInt ( web . Params ( c . Req ) [ ":userId" ] , 10 , 64 )
2022-01-14 10:55:57 -06:00
if err != nil {
return response . Error ( http . StatusBadRequest , "userId is invalid" , err )
}
2022-06-27 11:40:12 -05:00
return hs . updateOrgUserHelper ( c , cmd )
2015-05-19 03:16:32 -05:00
}
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) updateOrgUserHelper ( c * contextmodel . ReqContext , cmd org . UpdateOrgUserCommand ) response . Response {
2015-05-01 02:48:07 -05:00
if ! cmd . Role . IsValid ( ) {
2023-02-03 07:37:41 -06:00
return response . Error ( http . StatusBadRequest , "Invalid role specified" , nil )
2015-05-01 02:48:07 -05:00
}
2023-08-28 03:42:24 -05:00
if ! c . SignedInUser . GetOrgRole ( ) . Includes ( cmd . Role ) && ! c . SignedInUser . GetIsGrafanaAdmin ( ) {
2022-06-27 11:40:12 -05:00
return response . Error ( http . StatusForbidden , "Cannot assign a role higher than user's role" , nil )
}
2023-07-25 04:51:47 -05:00
// we do not allow to change role for external synced users
qAuth := login . GetAuthInfoQuery { UserId : cmd . UserID }
authInfo , err := hs . authInfoService . GetAuthInfo ( c . Req . Context ( ) , & qAuth )
if err != nil {
if errors . Is ( err , user . ErrUserNotFound ) {
hs . log . Debug ( "Failed to get user auth info for basic auth user" , cmd . UserID , nil )
} else {
hs . log . Error ( "Failed to get user auth info for external sync check" , cmd . UserID , err )
return response . Error ( http . StatusInternalServerError , "Failed to get user auth info" , nil )
2023-03-22 12:41:59 -05:00
}
}
2023-07-25 04:51:47 -05:00
if authInfo != nil && authInfo . AuthModule != "" && login . IsExternallySynced ( hs . Cfg , authInfo . AuthModule ) {
2023-07-25 07:27:02 -05:00
// A GCom specific feature toggle for role locking has been introduced, as the previous implementation had a bug with locking down external users synced through GCom (https://github.com/grafana/grafana/pull/72044)
// Remove this conditional once FlagGcomOnlyExternalOrgRoleSync feature toggle has been removed
if authInfo . AuthModule != login . GrafanaComAuthModule || hs . Features . IsEnabled ( featuremgmt . FlagGcomOnlyExternalOrgRoleSync ) {
return response . Err ( org . ErrCannotChangeRoleForExternallySyncedUser . Errorf ( "Cannot change role for externally synced user" ) )
}
2023-07-25 04:51:47 -05:00
}
2022-09-26 03:27:38 -05:00
if err := hs . orgService . UpdateOrgUser ( c . Req . Context ( ) , & cmd ) ; err != nil {
2023-01-09 07:39:53 -06:00
if errors . Is ( err , org . ErrLastOrgAdmin ) {
2023-02-03 07:37:41 -06:00
return response . Error ( http . StatusBadRequest , "Cannot change role so that there is no organization admin left" , nil )
2015-05-19 04:47:14 -05:00
}
2023-02-03 07:37:41 -06:00
return response . Error ( http . StatusInternalServerError , "Failed update org user" , err )
}
2023-07-10 07:14:21 -05:00
hs . accesscontrolService . ClearUserPermissionCache ( & user . SignedInUser {
UserID : cmd . UserID ,
OrgID : cmd . OrgID ,
} )
2015-05-01 02:48:07 -05:00
2021-01-15 07:43:20 -06:00
return response . Success ( "Organization user updated" )
2015-05-01 02:48:07 -05:00
}
2022-07-27 08:54:37 -05:00
// swagger:route DELETE /org/users/{user_id} org removeOrgUserForCurrentOrg
//
2022-09-12 02:40:35 -05:00
// Delete user in current organization.
2022-07-27 08:54:37 -05:00
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `org.users:remove` with scope `users:*`.
//
// Responses:
// 200: okResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) RemoveOrgUserForCurrentOrg ( c * contextmodel . ReqContext ) response . Response {
2022-01-14 10:55:57 -06:00
userId , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":userId" ] , 10 , 64 )
if err != nil {
return response . Error ( http . StatusBadRequest , "userId is invalid" , err )
}
2022-09-26 11:53:17 -05:00
return hs . removeOrgUserHelper ( c . Req . Context ( ) , & org . RemoveOrgUserCommand {
UserID : userId ,
2023-08-28 03:42:24 -05:00
OrgID : c . SignedInUser . GetOrgID ( ) ,
2018-10-11 00:48:35 -05:00
ShouldDeleteOrphanedUser : true ,
} )
2015-05-19 03:16:32 -05:00
}
2022-07-27 08:54:37 -05:00
// swagger:route DELETE /orgs/{org_id}/users/{user_id} orgs removeOrgUser
//
2022-09-12 02:40:35 -05:00
// Delete user in current organization.
2022-07-27 08:54:37 -05:00
//
// If you are running Grafana Enterprise and have Fine-grained access control enabled
// you need to have a permission with action: `org.users:remove` with scope `users:*`.
//
// Responses:
// 200: okResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2023-01-27 01:50:36 -06:00
func ( hs * HTTPServer ) RemoveOrgUser ( c * contextmodel . ReqContext ) response . Response {
2022-01-14 10:55:57 -06:00
userId , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":userId" ] , 10 , 64 )
if err != nil {
return response . Error ( http . StatusBadRequest , "userId is invalid" , err )
}
orgId , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":orgId" ] , 10 , 64 )
if err != nil {
return response . Error ( http . StatusBadRequest , "orgId is invalid" , err )
}
2022-09-26 11:53:17 -05:00
return hs . removeOrgUserHelper ( c . Req . Context ( ) , & org . RemoveOrgUserCommand {
UserID : userId ,
OrgID : orgId ,
2018-10-11 00:48:35 -05:00
} )
2015-05-19 03:16:32 -05:00
}
2015-01-19 11:01:04 -06:00
2022-09-26 11:53:17 -05:00
func ( hs * HTTPServer ) removeOrgUserHelper ( ctx context . Context , cmd * org . RemoveOrgUserCommand ) response . Response {
if err := hs . orgService . RemoveOrgUser ( ctx , cmd ) ; err != nil {
2023-01-09 07:39:53 -06:00
if errors . Is ( err , org . ErrLastOrgAdmin ) {
2021-01-15 07:43:20 -06:00
return response . Error ( 400 , "Cannot remove last organization admin" , nil )
2015-01-20 08:48:19 -06:00
}
2021-01-15 07:43:20 -06:00
return response . Error ( 500 , "Failed to remove user from organization" , err )
2015-01-19 11:01:04 -06:00
}
2018-10-11 14:20:53 -05:00
if cmd . UserWasDeleted {
2022-08-17 09:32:02 -05:00
// This should be called from appropriate service when moved
2022-09-26 11:53:17 -05:00
if err := hs . accesscontrolService . DeleteUserPermissions ( ctx , accesscontrol . GlobalOrgID , cmd . UserID ) ; err != nil {
hs . log . Warn ( "failed to delete permissions for user" , "userID" , cmd . UserID , "orgID" , accesscontrol . GlobalOrgID , "err" , err )
2022-08-17 09:32:02 -05:00
}
2021-01-15 07:43:20 -06:00
return response . Success ( "User deleted" )
2018-10-11 00:58:22 -05:00
}
2022-08-17 09:32:02 -05:00
// This should be called from appropriate service when moved
2022-09-26 11:53:17 -05:00
if err := hs . accesscontrolService . DeleteUserPermissions ( ctx , cmd . OrgID , cmd . UserID ) ; err != nil {
hs . log . Warn ( "failed to delete permissions for user" , "userID" , cmd . UserID , "orgID" , cmd . OrgID , "err" , err )
2022-08-17 09:32:02 -05:00
}
2021-01-15 07:43:20 -06:00
return response . Success ( "User removed from organization" )
2015-01-19 11:01:04 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:parameters addOrgUserToCurrentOrg
type AddOrgUserToCurrentOrgParams struct {
// in:body
// required:true
2023-01-09 07:39:53 -06:00
Body org . AddOrgUserCommand ` json:"body" `
2022-07-27 08:54:37 -05:00
}
// swagger:parameters addOrgUser
type AddOrgUserParams struct {
// in:body
// required:true
2023-01-09 07:39:53 -06:00
Body org . AddOrgUserCommand ` json:"body" `
2022-07-27 08:54:37 -05:00
// in:path
// required:true
OrgID int64 ` json:"org_id" `
}
// swagger:parameters getOrgUsersForCurrentOrgLookup
type LookupOrgUsersParams struct {
// in:query
// required:false
Query string ` json:"query" `
// in:query
// required:false
Limit int ` json:"limit" `
}
// swagger:parameters getOrgUsers
type GetOrgUsersParams struct {
// in:path
// required:true
OrgID int64 ` json:"org_id" `
}
// swagger:parameters updateOrgUserForCurrentOrg
type UpdateOrgUserForCurrentOrgParams struct {
// in:body
// required:true
2023-01-09 07:39:53 -06:00
Body org . UpdateOrgUserCommand ` json:"body" `
2022-07-27 08:54:37 -05:00
// in:path
// required:true
UserID int64 ` json:"user_id" `
}
// swagger:parameters updateOrgUser
type UpdateOrgUserParams struct {
// in:body
// required:true
2023-01-09 07:39:53 -06:00
Body org . UpdateOrgUserCommand ` json:"body" `
2022-07-27 08:54:37 -05:00
// in:path
// required:true
OrgID int64 ` json:"org_id" `
// in:path
// required:true
UserID int64 ` json:"user_id" `
}
// swagger:parameters removeOrgUserForCurrentOrg
type RemoveOrgUserForCurrentOrgParams struct {
// in:path
// required:true
UserID int64 ` json:"user_id" `
}
// swagger:parameters removeOrgUser
type RemoveOrgUserParams struct {
// in:path
// required:true
OrgID int64 ` json:"org_id" `
// in:path
// required:true
UserID int64 ` json:"user_id" `
}
2023-01-18 09:49:07 -06:00
// swagger:parameters searchOrgUsers
type SearchOrgUsersParams struct {
// in:path
// required:true
OrgID int64 ` json:"org_id" `
}
2022-07-27 08:54:37 -05:00
// swagger:response getOrgUsersForCurrentOrgLookupResponse
type GetOrgUsersForCurrentOrgLookupResponse struct {
// The response message
// in: body
Body [ ] * dtos . UserLookupDTO ` json:"body" `
}
// swagger:response getOrgUsersForCurrentOrgResponse
type GetOrgUsersForCurrentOrgResponse struct {
// The response message
// in: body
2023-01-09 07:39:53 -06:00
Body [ ] * org . OrgUserDTO ` json:"body" `
2022-07-27 08:54:37 -05:00
}
// swagger:response getOrgUsersResponse
type GetOrgUsersResponse struct {
2023-01-18 09:49:07 -06:00
// The response message/
2022-07-27 08:54:37 -05:00
// in: body
2023-01-09 07:39:53 -06:00
Body [ ] * org . OrgUserDTO ` json:"body" `
2022-07-27 08:54:37 -05:00
}
2023-01-18 09:49:07 -06:00
// swagger:response searchOrgUsersResponse
type SearchOrgUsersResponse struct {
// The response message
// in: body
Body * org . SearchOrgUsersQueryResult ` json:"body" `
}