add functionality to assign user to teams through oidc custom claim
This commit is contained in:
parent
d3fa4a04c0
commit
3ef25e7be5
|
@ -150,6 +150,7 @@ func HandleCallback(c echo.Context) error {
|
|||
|
||||
// Extract custom claims
|
||||
cl := &claims{}
|
||||
|
||||
err = idToken.Claims(cl)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting token claims for provider %s: %v", provider.Name, err)
|
||||
|
@ -204,57 +205,117 @@ func HandleCallback(c echo.Context) error {
|
|||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
||||
// Check if we have seen these teams before
|
||||
if len(cl.Teams) > 0 {
|
||||
teams, err := GetOrCreateTeamsByNames(s, cl.Teams, u)
|
||||
// does the oidc token contain well formed "vikunja_groups" through vikunja_scope
|
||||
teamData, err := getTeamDataFromToken(cl.VikunjaGroups, provider)
|
||||
if err != nil {
|
||||
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.
|
||||
if len(teamData) > 0 {
|
||||
log.Debugf("TeamData is set %v", teamData)
|
||||
teams, err := GetOrCreateTeamsByNames(s, teamData, u)
|
||||
if err != nil {
|
||||
log.Errorf("Error verifying team for name %v, got %v", cl.Name, teams, err)
|
||||
return err
|
||||
} else {
|
||||
for _, team := range teams {
|
||||
tm := models.TeamMember{TeamID: team.ID, Username: u.Username}
|
||||
err := tm.CheckMembership(s)
|
||||
if err == nil {
|
||||
tm.Create(s, u)
|
||||
}
|
||||
|
||||
for _, team := range teams {
|
||||
tm := models.TeamMember{TeamID: team.ID, Username: u.Username}
|
||||
exists, err := tm.CheckMembership(s)
|
||||
if !exists {
|
||||
err = tm.Create(s, u)
|
||||
if err != nil {
|
||||
log.Debugf("Could not assign %v to %v. %v", u.Username, team.Name, err)
|
||||
}
|
||||
} else {
|
||||
log.Debugf("Team exists? %v or error: %v", exists, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = s.Commit()
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
log.Errorf("Error creating new Team for provider %s: %v", provider.Name, err)
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
// Create token
|
||||
return auth.NewUserAuthTokenResponse(u, c, false)
|
||||
}
|
||||
|
||||
func GetOrCreateTeamsByNames(s *xorm.Session, teamNames []string, u *user.User) (te []models.Team, err error) {
|
||||
te = []models.Team{}
|
||||
for _, t := range teamNames {
|
||||
team, err := models.GetTeamsByName(s, t)
|
||||
|
||||
// if team does not exists, create it
|
||||
if models.IsErrTeamsDoNotExist(err) {
|
||||
log.Debugf("No such Team: %v, create %v ..", t, team)
|
||||
tea := &models.Team{
|
||||
Name: t,
|
||||
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
|
||||
if team["name"] != nil {
|
||||
name = team["name"].(string)
|
||||
}
|
||||
err := tea.Create(s, u)
|
||||
if err != nil {
|
||||
log.Errorf("Teams: %v, err: %v", tea, err)
|
||||
} else {
|
||||
te = append(te, *tea)
|
||||
if team["description"] != nil {
|
||||
description = team["description"].(string)
|
||||
}
|
||||
} else {
|
||||
// if multiple teams with same name are found,
|
||||
if len(team) == 1 {
|
||||
// append team to return value
|
||||
te = append(te, *team[len(team)-1])
|
||||
} else {
|
||||
log.Debugf("Multiple Teams have the same name: %v, ignore assignment of %v", team[len(team)-1].Name, u.Name)
|
||||
if team["oidcID"] != nil {
|
||||
switch t := team["oidcID"].(type) {
|
||||
case int64:
|
||||
oidcID = fmt.Sprintf("%v", team["oidcID"])
|
||||
case string:
|
||||
oidcID = string(team["oidcID"].(string))
|
||||
case float64:
|
||||
fl := float64(team["oidcID"].(float64))
|
||||
oidcID = fmt.Sprintf("%v", fl)
|
||||
default:
|
||||
log.Errorf("No oidcID assigned for %v or type %v not supported", team, t)
|
||||
}
|
||||
}
|
||||
if name == "" || oidcID == "" {
|
||||
log.Errorf("Claim of your custom scope does not hold name or oidcID for automatic group assignment through oidc provider. Please check %s", provider.Name)
|
||||
return teamData, &user.ErrOpenIDCustomScopeMalformed{}
|
||||
}
|
||||
teamData = append(teamData, TeamData{TeamName: name, OidcID: oidcID, Description: description})
|
||||
}
|
||||
}
|
||||
return teamData, nil
|
||||
}
|
||||
|
||||
func CreateTeamWithData(s *xorm.Session, teamData TeamData, u *user.User) (team *models.Team, err error) {
|
||||
tea := &models.Team{
|
||||
Name: teamData.TeamName,
|
||||
Description: teamData.Description,
|
||||
OidcID: teamData.OidcID,
|
||||
}
|
||||
log.Debugf("Teams: %v", tea.OidcID)
|
||||
|
||||
err = tea.Create(s, u)
|
||||
return tea, err
|
||||
}
|
||||
|
||||
// this functions creates an array of existing teams that was generated from the oidc data.
|
||||
func GetOrCreateTeamsByNames(s *xorm.Session, teamData []TeamData, u *user.User) (te []models.Team, err error) {
|
||||
te = []models.Team{}
|
||||
// Procedure can only be successful if oidcID is set and converted to string
|
||||
for _, oidcTeam := range teamData {
|
||||
team, err := models.GetTeamByOidcIDAndName(s, oidcTeam.OidcID, oidcTeam.TeamName)
|
||||
if err != nil {
|
||||
log.Debugf("Team with oidc_id %v and name %v does not exist. Create Team.. ", oidcTeam.OidcID, oidcTeam.TeamName)
|
||||
newTeam, err := CreateTeamWithData(s, oidcTeam, u)
|
||||
if err != nil {
|
||||
return te, err
|
||||
}
|
||||
te = append(te, *newTeam)
|
||||
} else {
|
||||
log.Debugf("Team with oidc_id %v and name %v already exists.", team.OidcID, team.Name)
|
||||
te = append(te, team)
|
||||
}
|
||||
|
||||
}
|
||||
log.Debugf("Array: %v", te)
|
||||
return te, err
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue