aboutsummaryrefslogtreecommitdiffstats
path: root/routers/web/auth/oauth.go
diff options
context:
space:
mode:
Diffstat (limited to 'routers/web/auth/oauth.go')
-rw-r--r--routers/web/auth/oauth.go93
1 files changed, 62 insertions, 31 deletions
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index 277f8bed31..f1c155e78f 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -4,6 +4,7 @@
package auth
import (
+ "encoding/gob"
"errors"
"fmt"
"html"
@@ -18,8 +19,8 @@ import (
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
+ "code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/web/middleware"
source_service "code.gitea.io/gitea/services/auth/source"
"code.gitea.io/gitea/services/auth/source/oauth2"
@@ -34,9 +35,8 @@ import (
// SignInOAuth handles the OAuth2 login buttons
func SignInOAuth(ctx *context.Context) {
- provider := ctx.PathParam("provider")
-
- authSource, err := auth.GetActiveOAuth2SourceByName(ctx, provider)
+ authName := ctx.PathParam("provider")
+ authSource, err := auth.GetActiveOAuth2SourceByAuthName(ctx, authName)
if err != nil {
ctx.ServerError("SignIn", err)
return
@@ -73,8 +73,6 @@ func SignInOAuth(ctx *context.Context) {
// SignInOAuthCallback handles the callback from the given provider
func SignInOAuthCallback(ctx *context.Context) {
- provider := ctx.PathParam("provider")
-
if ctx.Req.FormValue("error") != "" {
var errorKeyValues []string
for k, vv := range ctx.Req.Form {
@@ -87,7 +85,8 @@ func SignInOAuthCallback(ctx *context.Context) {
}
// first look if the provider is still active
- authSource, err := auth.GetActiveOAuth2SourceByName(ctx, provider)
+ authName := ctx.PathParam("provider")
+ authSource, err := auth.GetActiveOAuth2SourceByAuthName(ctx, authName)
if err != nil {
ctx.ServerError("SignIn", err)
return
@@ -132,7 +131,7 @@ func SignInOAuthCallback(ctx *context.Context) {
if u == nil {
if ctx.Doer != nil {
// attach user to the current signed-in user
- err = externalaccount.LinkAccountToUser(ctx, ctx.Doer, gothUser)
+ err = externalaccount.LinkAccountToUser(ctx, authSource.ID, ctx.Doer, gothUser)
if err != nil {
ctx.ServerError("UserLinkAccount", err)
return
@@ -155,9 +154,10 @@ func SignInOAuthCallback(ctx *context.Context) {
return
}
if uname == "" {
- if setting.OAuth2Client.Username == setting.OAuth2UsernameNickname {
+ switch setting.OAuth2Client.Username {
+ case setting.OAuth2UsernameNickname:
missingFields = append(missingFields, "nickname")
- } else if setting.OAuth2Client.Username == setting.OAuth2UsernamePreferredUsername {
+ case setting.OAuth2UsernamePreferredUsername:
missingFields = append(missingFields, "preferred_username")
} // else: "UserID" and "Email" have been handled above separately
}
@@ -172,12 +172,11 @@ func SignInOAuthCallback(ctx *context.Context) {
gothUser.RawData = make(map[string]any)
}
gothUser.RawData["__giteaAutoRegMissingFields"] = missingFields
- showLinkingLogin(ctx, gothUser)
+ showLinkingLogin(ctx, authSource.ID, gothUser)
return
}
u = &user_model.User{
Name: uname,
- FullName: gothUser.Name,
Email: gothUser.Email,
LoginType: auth.OAuth2,
LoginSource: authSource.ID,
@@ -191,10 +190,14 @@ func SignInOAuthCallback(ctx *context.Context) {
source := authSource.Cfg.(*oauth2.Source)
isAdmin, isRestricted := getUserAdminAndRestrictedFromGroupClaims(source, &gothUser)
- u.IsAdmin = isAdmin.ValueOrDefault(false)
- u.IsRestricted = isRestricted.ValueOrDefault(false)
+ u.IsAdmin = isAdmin.ValueOrDefault(user_service.UpdateOptionField[bool]{FieldValue: false}).FieldValue
+ u.IsRestricted = isRestricted.ValueOrDefault(setting.Service.DefaultUserIsRestricted)
- if !createAndHandleCreatedUser(ctx, templates.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) {
+ linkAccountData := &LinkAccountData{authSource.ID, gothUser}
+ if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingDisabled {
+ linkAccountData = nil
+ }
+ if !createAndHandleCreatedUser(ctx, "", nil, u, overwriteDefault, linkAccountData) {
// error already handled
return
}
@@ -205,7 +208,7 @@ func SignInOAuthCallback(ctx *context.Context) {
}
} else {
// no existing user is found, request attach or new account
- showLinkingLogin(ctx, gothUser)
+ showLinkingLogin(ctx, authSource.ID, gothUser)
return
}
}
@@ -256,11 +259,11 @@ func getClaimedGroups(source *oauth2.Source, gothUser *goth.User) container.Set[
return claimValueToStringSet(groupClaims)
}
-func getUserAdminAndRestrictedFromGroupClaims(source *oauth2.Source, gothUser *goth.User) (isAdmin, isRestricted optional.Option[bool]) {
+func getUserAdminAndRestrictedFromGroupClaims(source *oauth2.Source, gothUser *goth.User) (isAdmin optional.Option[user_service.UpdateOptionField[bool]], isRestricted optional.Option[bool]) {
groups := getClaimedGroups(source, gothUser)
if source.AdminGroup != "" {
- isAdmin = optional.Some(groups.Contains(source.AdminGroup))
+ isAdmin = user_service.UpdateOptionFieldFromSync(groups.Contains(source.AdminGroup))
}
if source.RestrictedGroup != "" {
isRestricted = optional.Some(groups.Contains(source.RestrictedGroup))
@@ -269,17 +272,36 @@ func getUserAdminAndRestrictedFromGroupClaims(source *oauth2.Source, gothUser *g
return isAdmin, isRestricted
}
-func showLinkingLogin(ctx *context.Context, gothUser goth.User) {
- if err := updateSession(ctx, nil, map[string]any{
- "linkAccountGothUser": gothUser,
- }); err != nil {
- ctx.ServerError("updateSession", err)
+type LinkAccountData struct {
+ AuthSourceID int64
+ GothUser goth.User
+}
+
+func oauth2GetLinkAccountData(ctx *context.Context) *LinkAccountData {
+ gob.Register(LinkAccountData{})
+ v, ok := ctx.Session.Get("linkAccountData").(LinkAccountData)
+ if !ok {
+ return nil
+ }
+ return &v
+}
+
+func Oauth2SetLinkAccountData(ctx *context.Context, linkAccountData LinkAccountData) error {
+ gob.Register(LinkAccountData{})
+ return updateSession(ctx, nil, map[string]any{
+ "linkAccountData": linkAccountData,
+ })
+}
+
+func showLinkingLogin(ctx *context.Context, authSourceID int64, gothUser goth.User) {
+ if err := Oauth2SetLinkAccountData(ctx, LinkAccountData{authSourceID, gothUser}); err != nil {
+ ctx.ServerError("Oauth2SetLinkAccountData", err)
return
}
ctx.Redirect(setting.AppSubURL + "/user/link_account")
}
-func updateAvatarIfNeed(ctx *context.Context, url string, u *user_model.User) {
+func oauth2UpdateAvatarIfNeed(ctx *context.Context, url string, u *user_model.User) {
if setting.OAuth2Client.UpdateAvatar && len(url) > 0 {
resp, err := http.Get(url)
if err == nil {
@@ -297,11 +319,14 @@ func updateAvatarIfNeed(ctx *context.Context, url string, u *user_model.User) {
}
}
-func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model.User, gothUser goth.User) {
- updateAvatarIfNeed(ctx, gothUser.AvatarURL, u)
+func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_model.User, gothUser goth.User) {
+ oauth2SignInSync(ctx, authSource.ID, u, gothUser)
+ if ctx.Written() {
+ return
+ }
needs2FA := false
- if !source.Cfg.(*oauth2.Source).SkipLocalTwoFA {
+ if !authSource.TwoFactorShouldSkip() {
_, err := auth.GetTwoFactorByUID(ctx, u.ID)
if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) {
ctx.ServerError("UserSignIn", err)
@@ -310,7 +335,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
needs2FA = err == nil
}
- oauth2Source := source.Cfg.(*oauth2.Source)
+ oauth2Source := authSource.Cfg.(*oauth2.Source)
groupTeamMapping, err := auth_module.UnmarshalGroupTeamMapping(oauth2Source.GroupTeamMap)
if err != nil {
ctx.ServerError("UnmarshalGroupTeamMapping", err)
@@ -336,7 +361,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
}
}
- if err := externalaccount.EnsureLinkExternalToUser(ctx, u, gothUser); err != nil {
+ if err := externalaccount.EnsureLinkExternalToUser(ctx, authSource.ID, u, gothUser); err != nil {
ctx.ServerError("EnsureLinkExternalToUser", err)
return
}
@@ -351,10 +376,16 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
ctx.ServerError("UpdateUser", err)
return
}
+ userHasTwoFactorAuth, err := auth.HasTwoFactorOrWebAuthn(ctx, u.ID)
+ if err != nil {
+ ctx.ServerError("UpdateUser", err)
+ return
+ }
if err := updateSession(ctx, nil, map[string]any{
- "uid": u.ID,
- "uname": u.Name,
+ session.KeyUID: u.ID,
+ session.KeyUname: u.Name,
+ session.KeyUserHasTwoFactorAuth: userHasTwoFactorAuth,
}); err != nil {
ctx.ServerError("updateSession", err)
return