mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-05-12 22:10:25 +00:00
feat: allow sync quota groups with oauth2 auth source (#8554)
Implements synchronizing an external user's quota group with provided OAuth2 claim. This functionality will allow system administrators to manage user's quota groups automatically. Documentation is at forgejo/docs#1337 Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8554 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Co-authored-by: thezzisu <thezzisu@gmail.com> Co-committed-by: thezzisu <thezzisu@gmail.com>
This commit is contained in:
parent
1000a0da3a
commit
e31d67e0aa
15 changed files with 585 additions and 3 deletions
|
|
@ -191,6 +191,9 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
|
|||
GroupTeamMap: form.Oauth2GroupTeamMap,
|
||||
GroupTeamMapRemoval: form.Oauth2GroupTeamMapRemoval,
|
||||
AllowUsernameChange: form.AllowUsernameChange,
|
||||
QuotaGroupClaimName: form.Oauth2QuotaGroupClaimName,
|
||||
QuotaGroupMap: form.Oauth2QuotaGroupMap,
|
||||
QuotaGroupMapRemoval: form.Oauth2QuotaGroupMapRemoval,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1096,6 +1096,11 @@ func SignInOAuthCallback(ctx *context.Context) {
|
|||
ctx.ServerError("SyncGroupsToTeams", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := syncGroupsToQuotaGroups(ctx, source, &gothUser, u); err != nil {
|
||||
ctx.ServerError("SyncGroupsToQuotaGroups", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// no existing user is found, request attach or new account
|
||||
showLinkingLogin(ctx, gothUser)
|
||||
|
|
@ -1140,6 +1145,23 @@ func syncGroupsToTeams(ctx *context.Context, source *oauth2.Source, gothUser *go
|
|||
return nil
|
||||
}
|
||||
|
||||
func syncGroupsToQuotaGroups(ctx *context.Context, source *oauth2.Source, gothUser *goth.User, u *user_model.User) error {
|
||||
if source.QuotaGroupMap != "" || source.QuotaGroupMapRemoval {
|
||||
quotaGroupMapping, err := auth_module.UnmarshalQuotaGroupMapping(source.QuotaGroupMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
groups := getClaimedQuotaGroups(source, gothUser)
|
||||
|
||||
if err := source_service.SyncGroupsToQuotaGroups(ctx, u, groups, quotaGroupMapping, source.QuotaGroupMapRemoval); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getClaimedGroups(source *oauth2.Source, gothUser *goth.User) container.Set[string] {
|
||||
groupClaims, has := gothUser.RawData[source.GroupClaimName]
|
||||
if !has {
|
||||
|
|
@ -1149,6 +1171,15 @@ func getClaimedGroups(source *oauth2.Source, gothUser *goth.User) container.Set[
|
|||
return claimValueToStringSet(groupClaims)
|
||||
}
|
||||
|
||||
func getClaimedQuotaGroups(source *oauth2.Source, gothUser *goth.User) container.Set[string] {
|
||||
groupClaims, has := gothUser.RawData[source.QuotaGroupClaimName]
|
||||
if !has {
|
||||
return nil
|
||||
}
|
||||
|
||||
return claimValueToStringSet(groupClaims)
|
||||
}
|
||||
|
||||
func getUserAdminAndRestrictedFromGroupClaims(source *oauth2.Source, gothUser *goth.User) (isAdmin, isRestricted optional.Option[bool]) {
|
||||
groups := getClaimedGroups(source, gothUser)
|
||||
|
||||
|
|
@ -1262,8 +1293,14 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
|
|||
ctx.ServerError("UnmarshalGroupTeamMapping", err)
|
||||
return
|
||||
}
|
||||
quotaGroupMapping, err := auth_module.UnmarshalQuotaGroupMapping(oauth2Source.QuotaGroupMap)
|
||||
if err != nil {
|
||||
ctx.ServerError("UnmarshalQuotaGroupMapping", err)
|
||||
return
|
||||
}
|
||||
|
||||
groups := getClaimedGroups(oauth2Source, &gothUser)
|
||||
quotaGroups := getClaimedQuotaGroups(oauth2Source, &gothUser)
|
||||
|
||||
// If this user is enrolled in 2FA and this source doesn't override it,
|
||||
// we can't sign the user in just yet. Instead, redirect them to the 2FA authentication page.
|
||||
|
|
@ -1291,6 +1328,13 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
|
|||
}
|
||||
}
|
||||
|
||||
if oauth2Source.QuotaGroupMap != "" || oauth2Source.QuotaGroupMapRemoval {
|
||||
if err := source_service.SyncGroupsToQuotaGroups(ctx, u, quotaGroups, quotaGroupMapping, oauth2Source.QuotaGroupMapRemoval); err != nil {
|
||||
ctx.ServerError("SyncGroupsToQuotaGroups", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// update external user information
|
||||
if err := externalaccount.UpdateExternalUser(ctx, u, gothUser); err != nil {
|
||||
if !errors.Is(err, util.ErrNotExist) {
|
||||
|
|
@ -1329,6 +1373,13 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
|
|||
}
|
||||
}
|
||||
|
||||
if oauth2Source.QuotaGroupMap != "" || oauth2Source.QuotaGroupMapRemoval {
|
||||
if err := source_service.SyncGroupsToQuotaGroups(ctx, u, quotaGroups, quotaGroupMapping, oauth2Source.QuotaGroupMapRemoval); err != nil {
|
||||
ctx.ServerError("SyncGroupsToQuotaGroups", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := updateSession(ctx, nil, map[string]any{
|
||||
// User needs to use 2FA, save data and redirect to 2FA page.
|
||||
"twofaUid": u.ID,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue