OIDC groups implementation
- Add Groups field to User struct with JSON storage - Include GetGroups() and SetGroups() helper methods - Extract groups from OIDC claims in FromClaim() - Add database migration 202509161200 for groups column - Update config-example.yaml with groups scope - Add comprehensive documentation and testing
This commit is contained in:
parent
30d12dafed
commit
5abc3c87b2
29 changed files with 5088 additions and 3 deletions
|
|
@ -68,6 +68,11 @@ type User struct {
|
|||
Provider string
|
||||
|
||||
ProfilePicURL string
|
||||
|
||||
// Groups stores the OIDC groups/roles that the user belongs to.
|
||||
// This is populated from the 'groups' claim in OIDC tokens and
|
||||
// is used for role-based access control in Headplane.
|
||||
Groups string `gorm:"type:text"`
|
||||
}
|
||||
|
||||
func (u *User) StringID() string {
|
||||
|
|
@ -104,6 +109,39 @@ func (u *User) profilePicURL() string {
|
|||
return u.ProfilePicURL
|
||||
}
|
||||
|
||||
// GetGroups returns the user's groups as a slice of strings.
|
||||
// Groups are stored as JSON in the database.
|
||||
func (u *User) GetGroups() []string {
|
||||
if u.Groups == "" {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
var groups []string
|
||||
if err := json.Unmarshal([]byte(u.Groups), &groups); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to unmarshal user groups")
|
||||
return []string{}
|
||||
}
|
||||
|
||||
return groups
|
||||
}
|
||||
|
||||
// SetGroups stores the user's groups as JSON in the database.
|
||||
func (u *User) SetGroups(groups []string) {
|
||||
if len(groups) == 0 {
|
||||
u.Groups = ""
|
||||
return
|
||||
}
|
||||
|
||||
data, err := json.Marshal(groups)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to marshal user groups")
|
||||
u.Groups = ""
|
||||
return
|
||||
}
|
||||
|
||||
u.Groups = string(data)
|
||||
}
|
||||
|
||||
func (u *User) TailscaleUser() *tailcfg.User {
|
||||
user := tailcfg.User{
|
||||
ID: tailcfg.UserID(u.ID),
|
||||
|
|
@ -341,4 +379,7 @@ func (u *User) FromClaim(claims *OIDCClaims) {
|
|||
u.DisplayName = claims.Name
|
||||
u.ProfilePicURL = claims.ProfilePictureURL
|
||||
u.Provider = util.RegisterMethodOIDC
|
||||
|
||||
// Store OIDC groups for role-based access control
|
||||
u.SetGroups(claims.Groups)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue