add functionality for deleting user only from oidc teams which are not present in the current token

This commit is contained in:
viehlieb 2023-01-27 17:15:50 +01:00
parent 4dc2547e09
commit 625d847e9f
3 changed files with 117 additions and 9 deletions

View File

@ -1099,7 +1099,6 @@ func (err ErrTeamNameCannotBeEmpty) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeTeamNameCannotBeEmpty, Message: "The team name cannot be empty"}
}
// ErrTeamDoesNotExist represents an error where a team does not exist
type ErrTeamDoesNotExist struct {
TeamID int64
}
@ -1218,6 +1217,51 @@ func (err ErrTeamDoesNotHaveAccessToProject) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusForbidden, Code: ErrCodeTeamDoesNotHaveAccessToProject, Message: "This team does not have access to the project."}
}
type ErrTeamsDoNotExist struct {
Name string
}
// IsErrTeamDoNotExist checks if an error is ErrTeamDoesNotExist.
func IsErrTeamsDoNotExist(err error) bool {
_, ok := err.(ErrTeamsDoNotExist)
return ok
}
func (err ErrTeamsDoNotExist) Error() string {
return fmt.Sprintf("Team does not exist [Team Name: %v]", err.Name)
}
// ErrCodeTeamDoesNotExist holds the unique world-error code of this error
const ErrCodeTeamsDoNotExist = 6008
// HTTPError holds the http error description
func (err ErrTeamsDoNotExist) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeTeamDoesNotExist, Message: "No team with given name exists."}
}
// ErrOIDCTeamsDoNotExistForUser represents an error where an oidcTeam does not exist for the user
type ErrOIDCTeamsDoNotExistForUser struct {
UserID int64
}
// IsErrOIDCTeamsDoNotExistForUser checks if an error is ErrOIDCTeamsDoNotExistForUser.
func IsErrOIDCTeamsDoNotExistForUser(err error) bool {
_, ok := err.(ErrTeamDoesNotExist)
return ok
}
func (err ErrOIDCTeamsDoNotExistForUser) Error() string {
return fmt.Sprintf("No Oidc exists for User [User ID: %d]", err.UserID)
}
// ErrCodeTeamDoesNotExist holds the unique world-error code of this error
const ErrCodeOIDCTeamsDoNotExistForUser = 6009
// HTTPError holds the http error description
func (err ErrOIDCTeamsDoNotExistForUser) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeTeamDoesNotExist, Message: "This team does not exist."}
}
// ====================
// User <-> Project errors
// ====================

View File

@ -94,6 +94,12 @@ type TeamUser struct {
TeamID int64 `json:"-"`
}
type TeamData struct {
TeamName string
OidcID string
Description string
}
// GetTeamByID gets a team by its ID
func GetTeamByID(s *xorm.Session, id int64) (team *Team, err error) {
if id < 1 {
@ -143,16 +149,30 @@ func GetTeamsByName(s *xorm.Session, name string) (teams []*Team, err error) {
// GetTeamByOidcIDAndName gets teams where oidc_id and name match parameters
// For oidc team creation oidcID and Name need to be set
func GetTeamByOidcIDAndName(s *xorm.Session, id string, name string) (team Team, err error) {
func GetTeamByOidcIDAndName(s *xorm.Session, oidcID string, teamName string) (team Team, err error) {
exists, err := s.
Table("teams").
Where("oidc_id = ? AND name = ?", id, name).
Where("oidc_id = ? AND name = ?", oidcID, teamName).
Get(&team)
log.Debugf("GetTeamByOidcIDAndName: %v, exists: %v", team.Name, exists)
if exists && err == nil {
return team, nil
}
return team, ErrTeamsDoNotExist{id}
return team, ErrTeamsDoNotExist{oidcID}
}
func FindAllOidcTeamIDsForUser(s *xorm.Session, userID int64) (ts []int64, err error) {
err = s.
Table("team_members").
Where("user_id = ? ", userID).
Join("RIGHT", "teams", "teams.id = team_members.team_id").
Where("teams.oidc_id != ?", "").
Cols("teams.id").
Find(&ts)
if ts == nil || err != nil {
return ts, ErrOIDCTeamsDoNotExistForUser{userID}
}
return ts, nil
}
func addMoreInfoToTeams(s *xorm.Session, teams []*Team) (err error) {

View File

@ -209,16 +209,22 @@ func HandleCallback(c echo.Context) error {
log.Errorf("Error creating teams for user and vikunja groups %s: %v", cl.VikunjaGroups, err)
return handler.HandleHTTPError(err, c)
}
// check if we have seen these teams before.
// find or create Teams and assign user as teammember.
//TODO: fix this error check
// nil is no problem
if len(teamData) > 0 {
//find old teams for user through oidc
oldOidcTeams, _ := models.FindAllOidcTeamIDsForUser(s, u.ID)
// check if we have seen these teams before.
// find or create Teams and assign user as teammember.
var oidcTeams []int64
log.Debugf("TeamData is set %v", teamData)
teams, err := GetOrCreateTeamsByOIDCAndNames(s, teamData, u)
if err != nil {
log.Errorf("Error verifying team for name %v, got %v", cl.Name, teams, err)
return err
}
for _, team := range teams {
tm := models.TeamMember{TeamID: team.ID, Username: u.Username}
exists, err := tm.CheckMembership(s)
@ -230,9 +236,10 @@ func HandleCallback(c echo.Context) error {
} else {
log.Debugf("Team exists? %v or error: %v", exists, err)
}
oidcTeams = append(oidcTeams, team.ID)
}
SignOutFromOrDeleteTeamsByID(s, u, notIn(oldOidcTeams, oidcTeams))
}
err = s.Commit()
if err != nil {
_ = s.Rollback()
@ -243,13 +250,30 @@ func HandleCallback(c echo.Context) error {
return auth.NewUserAuthTokenResponse(u, c, false)
}
func SignOutFromOrDeleteTeamsByID(s *xorm.Session, u *user.User, teamIDs []int64) {
for _, teamID := range teamIDs {
tm := models.TeamMember{TeamID: teamID, Username: u.Username}
err := tm.Delete(s, u)
if err != nil {
team, err := models.GetTeamByID(s, teamID)
if err != nil {
log.Errorf("Cannot find team with id: %v, err: %v", teamID, err)
} else {
err = team.Delete(s, u)
if err != nil {
log.Errorf("Cannot delete team %v", err)
}
}
}
}
}
func getTeamDataFromToken(groups interface{}, provider *Provider) (teamData []TeamData, err error) {
teamData = []TeamData{}
if groups != nil {
el := groups.([]interface{})
for _, data := range el {
team := data.(map[string]interface{})
log.Debugf("%s", team)
var name string
var description string
var oidcID string
@ -395,3 +419,23 @@ func getOrCreateUser(s *xorm.Session, cl *claims, issuer, subject string) (u *us
return
}
// find the elements which appear in slice1,but not in slice2
func notIn(slice1 []int64, slice2 []int64) []int64 {
var diff []int64
for _, s1 := range slice1 {
found := false
for _, s2 := range slice2 {
if s1 == s2 {
found = true
break
}
}
// String not found. We add it to return slice
if !found {
diff = append(diff, s1)
}
}
return diff
}