diff options
author | Joram Wilander <jwawilander@gmail.com> | 2017-01-23 08:12:05 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-23 08:12:05 -0500 |
commit | e9c9688b343049c6d461260bd15fff3486238f92 (patch) | |
tree | a112e51de0e7f9989b173b7dbc4ad89080cc0e34 /app | |
parent | b064457c745ae6bf27e5e6933a0a7406f3f4921d (diff) | |
download | chat-e9c9688b343049c6d461260bd15fff3486238f92.tar.gz chat-e9c9688b343049c6d461260bd15fff3486238f92.tar.bz2 chat-e9c9688b343049c6d461260bd15fff3486238f92.zip |
Move permissions code into app package (#5146)
* Move permissions code into app package
* Revert getPosts permission
Diffstat (limited to 'app')
-rw-r--r-- | app/authorization.go | 166 | ||||
-rw-r--r-- | app/authorization_test.go | 36 | ||||
-rw-r--r-- | app/team.go | 151 | ||||
-rw-r--r-- | app/user.go | 2 |
4 files changed, 341 insertions, 14 deletions
diff --git a/app/authorization.go b/app/authorization.go new file mode 100644 index 000000000..0f48b3c9d --- /dev/null +++ b/app/authorization.go @@ -0,0 +1,166 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + l4g "github.com/alecthomas/log4go" + "github.com/mattermost/platform/model" +) + +func SessionHasPermissionTo(session model.Session, permission *model.Permission) bool { + return CheckIfRolesGrantPermission(session.GetUserRoles(), permission.Id) +} + +func SessionHasPermissionToTeam(session model.Session, teamId string, permission *model.Permission) bool { + if teamId == "" { + return false + } + + teamMember := session.GetTeamByTeamId(teamId) + if teamMember != nil { + if CheckIfRolesGrantPermission(teamMember.GetRoles(), permission.Id) { + return true + } + } + + return SessionHasPermissionTo(session, permission) +} + +func SessionHasPermissionToChannel(session model.Session, channelId string, permission *model.Permission) bool { + if channelId == "" { + return false + } + + channelMember, err := GetChannelMember(channelId, session.UserId) + if err == nil { + roles := channelMember.GetRoles() + if CheckIfRolesGrantPermission(roles, permission.Id) { + return true + } + } + + var channel *model.Channel + channel, err = GetChannel(channelId) + if err == nil { + return SessionHasPermissionToTeam(session, channel.TeamId, permission) + } + + return SessionHasPermissionTo(session, permission) +} + +func SessionHasPermissionToChannelByPost(session model.Session, postId string, permission *model.Permission) bool { + var channelMember *model.ChannelMember + if result := <-Srv.Store.Channel().GetMemberForPost(postId, session.UserId); result.Err == nil { + channelMember = result.Data.(*model.ChannelMember) + + if CheckIfRolesGrantPermission(channelMember.GetRoles(), permission.Id) { + return true + } + } + + if result := <-Srv.Store.Channel().GetForPost(postId); result.Err == nil { + channel := result.Data.(*model.Channel) + return SessionHasPermissionToTeam(session, channel.TeamId, permission) + } + + return SessionHasPermissionTo(session, permission) +} + +func SessionHasPermissionToUser(session model.Session, userId string) bool { + if userId == "" { + return false + } + + if session.UserId == userId { + return true + } + + if SessionHasPermissionTo(session, model.PERMISSION_EDIT_OTHER_USERS) { + return true + } + + return false +} + +func HasPermissionTo(askingUserId string, permission *model.Permission) bool { + user, err := GetUser(askingUserId) + if err != nil { + return false + } + + roles := user.GetRoles() + + return CheckIfRolesGrantPermission(roles, permission.Id) +} + +func HasPermissionToTeam(askingUserId string, teamId string, permission *model.Permission) bool { + if teamId == "" || askingUserId == "" { + return false + } + + teamMember, err := GetTeamMember(teamId, askingUserId) + if err != nil { + return false + } + + roles := teamMember.GetRoles() + + if CheckIfRolesGrantPermission(roles, permission.Id) { + return true + } + + return HasPermissionTo(askingUserId, permission) +} + +func HasPermissionToChannel(askingUserId string, channelId string, permission *model.Permission) bool { + if channelId == "" || askingUserId == "" { + return false + } + + channelMember, err := GetChannelMember(channelId, askingUserId) + if err == nil { + roles := channelMember.GetRoles() + if CheckIfRolesGrantPermission(roles, permission.Id) { + return true + } + } + + var channel *model.Channel + channel, err = GetChannel(channelId) + if err == nil { + return HasPermissionToTeam(askingUserId, channel.TeamId, permission) + } + + return HasPermissionTo(askingUserId, permission) +} + +func HasPermissionToUser(askingUserId string, userId string) bool { + if askingUserId == userId { + return true + } + + if HasPermissionTo(askingUserId, model.PERMISSION_EDIT_OTHER_USERS) { + return true + } + + return false +} + +func CheckIfRolesGrantPermission(roles []string, permissionId string) bool { + for _, roleId := range roles { + if role, ok := model.BuiltInRoles[roleId]; !ok { + l4g.Debug("Bad role in system " + roleId) + return false + } else { + permissions := role.Permissions + for _, permission := range permissions { + if permission == permissionId { + return true + } + } + } + } + + return false +} diff --git a/app/authorization_test.go b/app/authorization_test.go new file mode 100644 index 000000000..049567483 --- /dev/null +++ b/app/authorization_test.go @@ -0,0 +1,36 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package app + +import ( + "testing" + + "github.com/mattermost/platform/model" +) + +func TestCheckIfRolesGrantPermission(t *testing.T) { + Setup() + + cases := []struct { + roles []string + permissionId string + shouldGrant bool + }{ + {[]string{model.ROLE_SYSTEM_ADMIN.Id}, model.ROLE_SYSTEM_ADMIN.Permissions[0], true}, + {[]string{model.ROLE_SYSTEM_ADMIN.Id}, "non-existant-permission", false}, + {[]string{model.ROLE_CHANNEL_USER.Id}, model.ROLE_CHANNEL_USER.Permissions[0], true}, + {[]string{model.ROLE_CHANNEL_USER.Id}, model.PERMISSION_MANAGE_SYSTEM.Id, false}, + {[]string{model.ROLE_SYSTEM_ADMIN.Id, model.ROLE_CHANNEL_USER.Id}, model.PERMISSION_MANAGE_SYSTEM.Id, true}, + {[]string{model.ROLE_CHANNEL_USER.Id, model.ROLE_SYSTEM_ADMIN.Id}, model.PERMISSION_MANAGE_SYSTEM.Id, true}, + {[]string{model.ROLE_TEAM_USER.Id, model.ROLE_TEAM_ADMIN.Id}, model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, true}, + {[]string{model.ROLE_TEAM_ADMIN.Id, model.ROLE_TEAM_USER.Id}, model.PERMISSION_MANAGE_SLASH_COMMANDS.Id, true}, + } + + for testnum, testcase := range cases { + if CheckIfRolesGrantPermission(testcase.roles, testcase.permissionId) != testcase.shouldGrant { + t.Fatal("Failed test case ", testnum) + } + } + +} diff --git a/app/team.go b/app/team.go index 28d667268..aabdc0bfd 100644 --- a/app/team.go +++ b/app/team.go @@ -29,6 +29,57 @@ func CreateTeam(team *model.Team) (*model.Team, *model.AppError) { } } +func CreateTeamWithUser(team *model.Team, userId string) (*model.Team, *model.AppError) { + var user *model.User + var err *model.AppError + if user, err = GetUser(userId); err != nil { + return nil, err + } else { + team.Email = user.Email + } + + if !isTeamEmailAllowed(user) { + return nil, model.NewLocAppError("isTeamEmailAllowed", "api.team.is_team_creation_allowed.domain.app_error", nil, "") + } + + var rteam *model.Team + if rteam, err = CreateTeam(team); err != nil { + return nil, err + } + + if err = JoinUserToTeam(rteam, user); err != nil { + return nil, err + } + + return rteam, nil +} + +func isTeamEmailAllowed(user *model.User) bool { + email := strings.ToLower(user.Email) + + if len(user.AuthService) > 0 && len(*user.AuthData) > 0 { + return true + } + + // commas and @ signs are optional + // can be in the form of "@corp.mattermost.com, mattermost.com mattermost.org" -> corp.mattermost.com mattermost.com mattermost.org + domains := strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(utils.Cfg.TeamSettings.RestrictCreationToDomains, "@", " ", -1), ",", " ", -1)))) + + matched := false + for _, d := range domains { + if strings.HasSuffix(email, "@"+d) { + matched = true + break + } + } + + if len(utils.Cfg.TeamSettings.RestrictCreationToDomains) > 0 && !matched { + return false + } + + return true +} + func UpdateTeam(team *model.Team) (*model.Team, *model.AppError) { var oldTeam *model.Team var err *model.AppError @@ -47,6 +98,12 @@ func UpdateTeam(team *model.Team) (*model.Team, *model.AppError) { return nil, result.Err } + oldTeam.Sanitize() + + message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_UPDATE_TEAM, "", "", "", nil) + message.Add("team", oldTeam.ToJson()) + go Publish(message) + return oldTeam, nil } @@ -80,7 +137,32 @@ func UpdateTeamMemberRoles(teamId string, userId string, newRoles string) (*mode return member, nil } -func JoinUserToTeamById(teamId string, user *model.User) *model.AppError { +func AddUserToTeam(teamId string, userId string) (*model.Team, *model.AppError) { + tchan := Srv.Store.Team().Get(teamId) + uchan := Srv.Store.User().Get(userId) + + var team *model.Team + if result := <-tchan; result.Err != nil { + return nil, result.Err + } else { + team = result.Data.(*model.Team) + } + + var user *model.User + if result := <-uchan; result.Err != nil { + return nil, result.Err + } else { + user = result.Data.(*model.User) + } + + if err := JoinUserToTeam(team, user); err != nil { + return nil, err + } + + return team, nil +} + +func AddUserToTeamByTeamId(teamId string, user *model.User) *model.AppError { if result := <-Srv.Store.Team().Get(teamId); result.Err != nil { return result.Err } else { @@ -88,7 +170,7 @@ func JoinUserToTeamById(teamId string, user *model.User) *model.AppError { } } -func JoinUserToTeamByHash(userId string, hash string, data string) (*model.Team, *model.AppError) { +func AddUserToTeamByHash(userId string, hash string, data string) (*model.Team, *model.AppError) { props := model.MapFromJson(strings.NewReader(data)) if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) { @@ -100,15 +182,21 @@ func JoinUserToTeamByHash(userId string, hash string, data string) (*model.Team, return nil, model.NewLocAppError("JoinUserToTeamByHash", "api.user.create_user.signup_link_expired.app_error", nil, "") } + tchan := Srv.Store.Team().Get(props["id"]) + uchan := Srv.Store.User().Get(userId) + var team *model.Team - var err *model.AppError - if team, err = GetTeam(props["id"]); err != nil { - return nil, err + if result := <-tchan; result.Err != nil { + return nil, result.Err + } else { + team = result.Data.(*model.Team) } var user *model.User - if user, err = GetUser(userId); err != nil { - return nil, err + if result := <-uchan; result.Err != nil { + return nil, result.Err + } else { + user = result.Data.(*model.User) } if err := JoinUserToTeam(team, user); err != nil { @@ -118,16 +206,22 @@ func JoinUserToTeamByHash(userId string, hash string, data string) (*model.Team, return team, nil } -func JoinUserToTeamByInviteId(inviteId string, userId string) (*model.Team, *model.AppError) { +func AddUserToTeamByInviteId(inviteId string, userId string) (*model.Team, *model.AppError) { + tchan := Srv.Store.Team().GetByInviteId(inviteId) + uchan := Srv.Store.User().Get(userId) + var team *model.Team - var err *model.AppError - if team, err = GetTeamByInviteId(inviteId); err != nil { - return nil, err + if result := <-tchan; result.Err != nil { + return nil, result.Err + } else { + team = result.Data.(*model.Team) } var user *model.User - if user, err = GetUser(userId); err != nil { - return nil, err + if result := <-uchan; result.Err != nil { + return nil, result.Err + } else { + user = result.Data.(*model.User) } if err := JoinUserToTeam(team, user); err != nil { @@ -266,6 +360,31 @@ func GetTeamMembersByIds(teamId string, userIds []string) ([]*model.TeamMember, } } +func RemoveUserFromTeam(teamId string, userId string) *model.AppError { + tchan := Srv.Store.Team().Get(teamId) + uchan := Srv.Store.User().Get(userId) + + var team *model.Team + if result := <-tchan; result.Err != nil { + return result.Err + } else { + team = result.Data.(*model.Team) + } + + var user *model.User + if result := <-uchan; result.Err != nil { + return result.Err + } else { + user = result.Data.(*model.User) + } + + if err := LeaveTeam(team, user); err != nil { + return err + } + + return nil +} + func LeaveTeam(team *model.Team, user *model.User) *model.AppError { var teamMember *model.TeamMember var err *model.AppError @@ -325,6 +444,12 @@ func LeaveTeam(team *model.Team, user *model.User) *model.AppError { } func InviteNewUsersToTeam(emailList []string, teamId, senderId, siteURL string) *model.AppError { + if len(emailList) == 0 { + err := model.NewLocAppError("InviteNewUsersToTeam", "api.team.invite_members.no_one.app_error", nil, "") + err.StatusCode = http.StatusBadRequest + return err + } + tchan := Srv.Store.Team().Get(teamId) uchan := Srv.Store.User().Get(senderId) diff --git a/app/user.go b/app/user.go index 8324417e8..dbff914d9 100644 --- a/app/user.go +++ b/app/user.go @@ -203,7 +203,7 @@ func CreateOAuthUser(service string, userData io.Reader, teamId string) (*model. } if len(teamId) > 0 { - err = JoinUserToTeamById(teamId, user) + err = AddUserToTeamByTeamId(teamId, user) if err != nil { return nil, err } |