diff options
Diffstat (limited to 'routers/web')
-rw-r--r-- | routers/web/admin/auths.go | 84 | ||||
-rw-r--r-- | routers/web/auth/auth.go | 35 | ||||
-rw-r--r-- | routers/web/auth/linkaccount.go | 45 | ||||
-rw-r--r-- | routers/web/auth/oauth.go | 19 | ||||
-rw-r--r-- | routers/web/auth/openid.go | 5 | ||||
-rw-r--r-- | routers/web/auth/saml.go | 172 | ||||
-rw-r--r-- | routers/web/web.go | 5 |
7 files changed, 39 insertions, 326 deletions
diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index 187b569d39..7fdd18dfae 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -1,12 +1,9 @@ // Copyright 2014 The Gogs Authors. All rights reserved. -// Copyright 2024 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package admin import ( - "crypto/tls" - "crypto/x509" "errors" "fmt" "net/http" @@ -28,7 +25,6 @@ import ( "code.gitea.io/gitea/services/auth/source/ldap" "code.gitea.io/gitea/services/auth/source/oauth2" pam_service "code.gitea.io/gitea/services/auth/source/pam" - "code.gitea.io/gitea/services/auth/source/saml" "code.gitea.io/gitea/services/auth/source/smtp" "code.gitea.io/gitea/services/auth/source/sspi" "code.gitea.io/gitea/services/forms" @@ -75,7 +71,6 @@ var ( {auth.SMTP.String(), auth.SMTP}, {auth.OAuth2.String(), auth.OAuth2}, {auth.SSPI.String(), auth.SSPI}, - {auth.SAML.String(), auth.SAML}, } if pam.Supported { items = append(items, dropdownItem{auth.Names[auth.PAM], auth.PAM}) @@ -88,16 +83,6 @@ var ( {ldap.SecurityProtocolNames[ldap.SecurityProtocolLDAPS], ldap.SecurityProtocolLDAPS}, {ldap.SecurityProtocolNames[ldap.SecurityProtocolStartTLS], ldap.SecurityProtocolStartTLS}, } - - nameIDFormats = []dropdownItem{ - {saml.NameIDFormatNames[saml.SAML20Persistent], saml.SAML20Persistent}, // use this as default value - {saml.NameIDFormatNames[saml.SAML11Email], saml.SAML11Email}, - {saml.NameIDFormatNames[saml.SAML11Persistent], saml.SAML11Persistent}, - {saml.NameIDFormatNames[saml.SAML11Unspecified], saml.SAML11Unspecified}, - {saml.NameIDFormatNames[saml.SAML20Email], saml.SAML20Email}, - {saml.NameIDFormatNames[saml.SAML20Transient], saml.SAML20Transient}, - {saml.NameIDFormatNames[saml.SAML20Unspecified], saml.SAML20Unspecified}, - } ) // NewAuthSource render adding a new auth source page @@ -113,8 +98,6 @@ func NewAuthSource(ctx *context.Context) { ctx.Data["is_sync_enabled"] = true ctx.Data["AuthSources"] = authSources ctx.Data["SecurityProtocols"] = securityProtocols - ctx.Data["CurrentNameIDFormat"] = saml.NameIDFormatNames[saml.SAML20Persistent] - ctx.Data["NameIDFormats"] = nameIDFormats ctx.Data["SMTPAuths"] = smtp.Authenticators oauth2providers := oauth2.GetSupportedOAuth2Providers() ctx.Data["OAuth2Providers"] = oauth2providers @@ -248,52 +231,6 @@ func parseSSPIConfig(ctx *context.Context, form forms.AuthenticationForm) (*sspi }, nil } -func parseSAMLConfig(ctx *context.Context, form forms.AuthenticationForm) (*saml.Source, error) { - if util.IsEmptyString(form.IdentityProviderMetadata) && util.IsEmptyString(form.IdentityProviderMetadataURL) { - return nil, fmt.Errorf("%s %s", ctx.Tr("form.SAMLMetadata"), ctx.Tr("form.require_error")) - } - - if !util.IsEmptyString(form.IdentityProviderMetadataURL) { - _, err := url.Parse(form.IdentityProviderMetadataURL) - if err != nil { - return nil, fmt.Errorf("%s", ctx.Tr("form.SAMLMetadataURL")) - } - } - - // check the integrity of the certificate and private key (autogenerated if these form fields are blank) - if !util.IsEmptyString(form.ServiceProviderCertificate) && !util.IsEmptyString(form.ServiceProviderPrivateKey) { - keyPair, err := tls.X509KeyPair([]byte(form.ServiceProviderCertificate), []byte(form.ServiceProviderPrivateKey)) - if err != nil { - return nil, err - } - keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0]) - if err != nil { - return nil, err - } - } else { - privateKey, cert, err := saml.GenerateSAMLSPKeypair() - if err != nil { - return nil, err - } - - form.ServiceProviderPrivateKey = privateKey - form.ServiceProviderCertificate = cert - } - - return &saml.Source{ - IdentityProviderMetadata: form.IdentityProviderMetadata, - IdentityProviderMetadataURL: form.IdentityProviderMetadataURL, - InsecureSkipAssertionSignatureValidation: form.InsecureSkipAssertionSignatureValidation, - NameIDFormat: saml.NameIDFormat(form.NameIDFormat), - ServiceProviderCertificate: form.ServiceProviderCertificate, - ServiceProviderPrivateKey: form.ServiceProviderPrivateKey, - EmailAssertionKey: form.EmailAssertionKey, - NameAssertionKey: form.NameAssertionKey, - UsernameAssertionKey: form.UsernameAssertionKey, - IconURL: form.SAMLIconURL, - }, nil -} - // NewAuthSourcePost response for adding an auth source func NewAuthSourcePost(ctx *context.Context) { form := *web.GetForm(ctx).(*forms.AuthenticationForm) @@ -307,8 +244,6 @@ func NewAuthSourcePost(ctx *context.Context) { ctx.Data["SMTPAuths"] = smtp.Authenticators oauth2providers := oauth2.GetSupportedOAuth2Providers() ctx.Data["OAuth2Providers"] = oauth2providers - ctx.Data["CurrentNameIDFormat"] = saml.NameIDFormatNames[saml.NameIDFormat(form.NameIDFormat)] - ctx.Data["NameIDFormats"] = nameIDFormats ctx.Data["SSPIAutoCreateUsers"] = true ctx.Data["SSPIAutoActivateUsers"] = true @@ -355,13 +290,6 @@ func NewAuthSourcePost(ctx *context.Context) { ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_of_type_exist"), tplAuthNew, form) return } - case auth.SAML: - var err error - config, err = parseSAMLConfig(ctx, form) - if err != nil { - ctx.RenderWithErr(err.Error(), tplAuthNew, form) - return - } default: ctx.Error(http.StatusBadRequest) return @@ -408,7 +336,6 @@ func EditAuthSource(ctx *context.Context) { ctx.Data["SMTPAuths"] = smtp.Authenticators oauth2providers := oauth2.GetSupportedOAuth2Providers() ctx.Data["OAuth2Providers"] = oauth2providers - ctx.Data["NameIDFormats"] = nameIDFormats source, err := auth.GetSourceByID(ctx, ctx.ParamsInt64(":authid")) if err != nil { @@ -417,9 +344,6 @@ func EditAuthSource(ctx *context.Context) { } ctx.Data["Source"] = source ctx.Data["HasTLS"] = source.HasTLS() - if source.IsSAML() { - ctx.Data["CurrentNameIDFormat"] = saml.NameIDFormatNames[source.Cfg.(*saml.Source).NameIDFormat] - } if source.IsOAuth2() { type Named interface { @@ -454,8 +378,6 @@ func EditAuthSourcePost(ctx *context.Context) { } ctx.Data["Source"] = source ctx.Data["HasTLS"] = source.HasTLS() - ctx.Data["CurrentNameIDFormat"] = saml.NameIDFormatNames[saml.SAML20Persistent] - ctx.Data["NameIDFormats"] = nameIDFormats if ctx.HasError() { ctx.HTML(http.StatusOK, tplAuthEdit) @@ -490,12 +412,6 @@ func EditAuthSourcePost(ctx *context.Context) { ctx.RenderWithErr(err.Error(), tplAuthEdit, form) return } - case auth.SAML: - config, err = parseSAMLConfig(ctx, form) - if err != nil { - ctx.RenderWithErr(err.Error(), tplAuthEdit, form) - return - } default: ctx.Error(http.StatusBadRequest) return diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index f5955ec5ff..3de1f3373d 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -28,7 +28,6 @@ import ( "code.gitea.io/gitea/routers/utils" auth_service "code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/auth/source/oauth2" - "code.gitea.io/gitea/services/auth/source/saml" "code.gitea.io/gitea/services/externalaccount" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/mailer" @@ -171,14 +170,6 @@ func SignIn(ctx *context.Context) { return } ctx.Data["OAuth2Providers"] = oauth2Providers - - samlProviders, err := saml.GetSAMLProviders(ctx, util.OptionalBoolTrue) - if err != nil { - ctx.ServerError("UserSignIn", err) - return - } - ctx.Data["SAMLProviders"] = samlProviders - ctx.Data["Title"] = ctx.Tr("sign_in") ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login" ctx.Data["PageIsSignIn"] = true @@ -202,14 +193,6 @@ func SignInPost(ctx *context.Context) { return } ctx.Data["OAuth2Providers"] = oauth2Providers - - samlProviders, err := saml.GetSAMLProviders(ctx, util.OptionalBoolTrue) - if err != nil { - ctx.ServerError("UserSignIn", err) - return - } - ctx.Data["SAMLProviders"] = samlProviders - ctx.Data["Title"] = ctx.Tr("sign_in") ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login" ctx.Data["PageIsSignIn"] = true @@ -521,7 +504,7 @@ func SignUpPost(ctx *context.Context) { Passwd: form.Password, } - if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, nil, false, auth.NoType) { + if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, nil, false) { // error already handled return } @@ -532,16 +515,16 @@ func SignUpPost(ctx *context.Context) { // createAndHandleCreatedUser calls createUserInContext and // then handleUserCreated. -func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool, authType auth.Type) bool { - if !createUserInContext(ctx, tpl, form, u, overwrites, gothUser, allowLink, authType) { +func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) bool { + if !createUserInContext(ctx, tpl, form, u, overwrites, gothUser, allowLink) { return false } - return handleUserCreated(ctx, u, gothUser, authType) + return handleUserCreated(ctx, u, gothUser) } // createUserInContext creates a user and handles errors within a given context. // Optionally a template can be specified. -func createUserInContext(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool, authType auth.Type) (ok bool) { +func createUserInContext(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) { if err := user_model.CreateUser(ctx, u, overwrites); err != nil { if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) { if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto { @@ -558,10 +541,10 @@ func createUserInContext(ctx *context.Context, tpl base.TplName, form any, u *us } // TODO: probably we should respect 'remember' user's choice... - linkAccount(ctx, user, *gothUser, true, authType) + linkAccount(ctx, user, *gothUser, true) return false // user is already created here, all redirects are handled } else if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingLogin { - showLinkingLogin(ctx, *gothUser, authType) + showLinkingLogin(ctx, *gothUser) return false // user will be created only after linking login } } @@ -607,7 +590,7 @@ func createUserInContext(ctx *context.Context, tpl base.TplName, form any, u *us // handleUserCreated does additional steps after a new user is created. // It auto-sets admin for the only user, updates the optional external user and // sends a confirmation email if required. -func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.User, authType auth.Type) (ok bool) { +func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.User) (ok bool) { // Auto-set admin for the only user. if user_model.CountUsers(ctx, nil) == 1 { opts := &user_service.UpdateOptions{ @@ -623,7 +606,7 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth. // update external user information if gothUser != nil { - if err := externalaccount.UpdateExternalUser(ctx, u, *gothUser, authType); err != nil { + if err := externalaccount.UpdateExternalUser(ctx, u, *gothUser); err != nil { if !errors.Is(err, util.ErrNotExist) { log.Error("UpdateExternalUser failed: %v", err) } diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index c62ae84083..1d94e52fe3 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -48,13 +48,13 @@ func LinkAccount(ctx *context.Context) { ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin" ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/link_account_signup" - externalLinkUser := ctx.Session.Get("linkAccountUser") - if externalLinkUser == nil { + gothUser := ctx.Session.Get("linkAccountGothUser") + if gothUser == nil { ctx.ServerError("UserSignIn", errors.New("not in LinkAccount session")) return } - gu := externalLinkUser.(auth.LinkAccountUser).GothUser + gu, _ := gothUser.(goth.User) uname, err := getUserName(&gu) if err != nil { ctx.ServerError("UserSignIn", err) @@ -135,14 +135,12 @@ func LinkAccountPostSignIn(ctx *context.Context) { ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin" ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/link_account_signup" - externalLinkUserInterface := ctx.Session.Get("linkAccountUser") - if externalLinkUserInterface == nil { + gothUser := ctx.Session.Get("linkAccountGothUser") + if gothUser == nil { ctx.ServerError("UserSignIn", errors.New("not in LinkAccount session")) return } - externalLinkUser := externalLinkUserInterface.(auth.LinkAccountUser) - if ctx.HasError() { ctx.HTML(http.StatusOK, tplLinkAccount) return @@ -154,10 +152,10 @@ func LinkAccountPostSignIn(ctx *context.Context) { return } - linkAccount(ctx, u, externalLinkUser.GothUser, signInForm.Remember, externalLinkUser.Type) + linkAccount(ctx, u, gothUser.(goth.User), signInForm.Remember) } -func linkAccount(ctx *context.Context, u *user_model.User, gothUser goth.User, remember bool, authType auth.Type) { +func linkAccount(ctx *context.Context, u *user_model.User, gothUser goth.User, remember bool) { updateAvatarIfNeed(ctx, gothUser.AvatarURL, u) // If this user is enrolled in 2FA, we can't sign the user in just yet. @@ -170,7 +168,7 @@ func linkAccount(ctx *context.Context, u *user_model.User, gothUser goth.User, r return } - err = externalaccount.LinkAccountToUser(ctx, u, gothUser, authType) + err = externalaccount.LinkAccountToUser(ctx, u, gothUser) if err != nil { ctx.ServerError("UserLinkAccount", err) return @@ -224,14 +222,14 @@ func LinkAccountPostRegister(ctx *context.Context) { ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin" ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/link_account_signup" - externalLinkUser := ctx.Session.Get("linkAccountUser") - if externalLinkUser == nil { + gothUserInterface := ctx.Session.Get("linkAccountGothUser") + if gothUserInterface == nil { ctx.ServerError("UserSignUp", errors.New("not in LinkAccount session")) return } - linkUser, ok := externalLinkUser.(auth.LinkAccountUser) + gothUser, ok := gothUserInterface.(goth.User) if !ok { - ctx.ServerError("UserSignUp", fmt.Errorf("session linkAccountUser type is %t but not goth.User", externalLinkUser)) + ctx.ServerError("UserSignUp", fmt.Errorf("session linkAccountGothUser type is %t but not goth.User", gothUserInterface)) return } @@ -277,7 +275,7 @@ func LinkAccountPostRegister(ctx *context.Context) { } } - authSource, err := auth.GetActiveAuthSourceByName(ctx, linkUser.GothUser.Provider, linkUser.Type) + authSource, err := auth.GetActiveOAuth2SourceByName(ctx, gothUser.Provider) if err != nil { ctx.ServerError("CreateUser", err) return @@ -287,24 +285,21 @@ func LinkAccountPostRegister(ctx *context.Context) { Name: form.UserName, Email: form.Email, Passwd: form.Password, - LoginType: authSource.Type, + LoginType: auth.OAuth2, LoginSource: authSource.ID, - LoginName: linkUser.GothUser.UserID, + LoginName: gothUser.UserID, } - if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, nil, &linkUser.GothUser, false, linkUser.Type) { + if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, nil, &gothUser, false) { // error already handled return } - if linkUser.Type == auth.OAuth2 { - source := authSource.Cfg.(*oauth2.Source) - if err := syncGroupsToTeams(ctx, source, &linkUser.GothUser, u); err != nil { - ctx.ServerError("SyncGroupsToTeams", err) - return - } + source := authSource.Cfg.(*oauth2.Source) + if err := syncGroupsToTeams(ctx, source, &gothUser, u); err != nil { + ctx.ServerError("SyncGroupsToTeams", err) + return } - // TODO we will support some form of group mapping for SAML handleSignIn(ctx, u, false) } diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 5e7368eb9a..33a4ae9192 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -841,7 +841,7 @@ func handleAuthorizeError(ctx *context.Context, authErr AuthorizeError, redirect func SignInOAuth(ctx *context.Context) { provider := ctx.Params(":provider") - authSource, err := auth.GetActiveAuthSourceByName(ctx, provider, auth.OAuth2) + authSource, err := auth.GetActiveOAuth2SourceByName(ctx, provider) if err != nil { ctx.ServerError("SignIn", err) return @@ -892,7 +892,7 @@ func SignInOAuthCallback(ctx *context.Context) { } // first look if the provider is still active - authSource, err := auth.GetActiveAuthSourceByName(ctx, provider, auth.OAuth2) + authSource, err := auth.GetActiveOAuth2SourceByName(ctx, provider) if err != nil { ctx.ServerError("SignIn", err) return @@ -935,7 +935,7 @@ func SignInOAuthCallback(ctx *context.Context) { if u == nil { if ctx.Doer != nil { // attach user to already logged in user - err = externalaccount.LinkAccountToUser(ctx, ctx.Doer, gothUser, auth.OAuth2) + err = externalaccount.LinkAccountToUser(ctx, ctx.Doer, gothUser) if err != nil { ctx.ServerError("UserLinkAccount", err) return @@ -988,7 +988,7 @@ func SignInOAuthCallback(ctx *context.Context) { u.IsAdmin = isAdmin.ValueOrDefault(false) u.IsRestricted = isRestricted.ValueOrDefault(false) - if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled, auth.OAuth2) { + if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) { // error already handled return } @@ -999,7 +999,7 @@ func SignInOAuthCallback(ctx *context.Context) { } } else { // no existing user is found, request attach or new account - showLinkingLogin(ctx, gothUser, auth.OAuth2) + showLinkingLogin(ctx, gothUser) return } } @@ -1063,12 +1063,9 @@ func getUserAdminAndRestrictedFromGroupClaims(source *oauth2.Source, gothUser *g return isAdmin, isRestricted } -func showLinkingLogin(ctx *context.Context, gothUser goth.User, authType auth.Type) { +func showLinkingLogin(ctx *context.Context, gothUser goth.User) { if err := updateSession(ctx, nil, map[string]any{ - "linkAccountUser": auth.LinkAccountUser{ - Type: authType, - GothUser: gothUser, - }, + "linkAccountGothUser": gothUser, }); err != nil { ctx.ServerError("updateSession", err) return @@ -1147,7 +1144,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model } // update external user information - if err := externalaccount.UpdateExternalUser(ctx, u, gothUser, auth.OAuth2); err != nil { + if err := externalaccount.UpdateExternalUser(ctx, u, gothUser); err != nil { if !errors.Is(err, util.ErrNotExist) { log.Error("UpdateExternalUser failed: %v", err) } diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index bf377b4496..29ef772b1c 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -8,7 +8,6 @@ import ( "net/http" "net/url" - auth_model "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/openid" "code.gitea.io/gitea/modules/base" @@ -364,7 +363,7 @@ func RegisterOpenIDPost(ctx *context.Context) { Email: form.Email, Passwd: password, } - if !createUserInContext(ctx, tplSignUpOID, form, u, nil, nil, false, auth_model.NoType) { + if !createUserInContext(ctx, tplSignUpOID, form, u, nil, nil, false) { // error already handled return } @@ -380,7 +379,7 @@ func RegisterOpenIDPost(ctx *context.Context) { return } - if !handleUserCreated(ctx, u, nil, auth_model.NoType) { + if !handleUserCreated(ctx, u, nil) { // error already handled return } diff --git a/routers/web/auth/saml.go b/routers/web/auth/saml.go deleted file mode 100644 index 29d689d2e9..0000000000 --- a/routers/web/auth/saml.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2024 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package auth - -import ( - "errors" - "fmt" - "net/http" - "strings" - - "code.gitea.io/gitea/models/auth" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/modules/web/middleware" - "code.gitea.io/gitea/services/auth/source/saml" - "code.gitea.io/gitea/services/externalaccount" - - "github.com/markbates/goth" -) - -func SignInSAML(ctx *context.Context) { - provider := ctx.Params(":provider") - - loginSource, err := auth.GetActiveAuthSourceByName(ctx, provider, auth.SAML) - if err != nil || loginSource == nil { - ctx.NotFound("SAMLMetadata", err) - return - } - - if err = loginSource.Cfg.(*saml.Source).Callout(ctx.Req, ctx.Resp); err != nil { - if strings.Contains(err.Error(), "no provider for ") { - ctx.Error(http.StatusNotFound) - return - } - ctx.ServerError("SignIn", err) - } -} - -func SignInSAMLCallback(ctx *context.Context) { - provider := ctx.Params(":provider") - loginSource, err := auth.GetActiveAuthSourceByName(ctx, provider, auth.SAML) - if err != nil || loginSource == nil { - ctx.NotFound("SignInSAMLCallback", err) - return - } - - if loginSource == nil { - ctx.ServerError("SignIn", fmt.Errorf("no valid provider found, check configured callback url in provider")) - return - } - - u, gothUser, err := samlUserLoginCallback(*ctx, loginSource, ctx.Req, ctx.Resp) - if err != nil { - ctx.ServerError("SignInSAMLCallback", err) - return - } - - if u == nil { - if ctx.Doer != nil { - // attach user to already logged in user - err = externalaccount.LinkAccountToUser(ctx, ctx.Doer, gothUser, auth.SAML) - if err != nil { - ctx.ServerError("LinkAccountToUser", err) - return - } - - ctx.Redirect(setting.AppSubURL + "/user/settings/security") - return - } else if !setting.Service.AllowOnlyInternalRegistration && false { - // TODO: allow auto registration from saml users (OAuth2 uses the following setting.OAuth2Client.EnableAutoRegistration) - } else { - // no existing user is found, request attach or new account - showLinkingLogin(ctx, gothUser, auth.SAML) - return - } - } - - handleSamlSignIn(ctx, loginSource, u, gothUser) -} - -func handleSamlSignIn(ctx *context.Context, source *auth.Source, u *user_model.User, gothUser goth.User) { - if err := updateSession(ctx, nil, map[string]any{ - "uid": u.ID, - "uname": u.Name, - }); err != nil { - ctx.ServerError("updateSession", err) - return - } - - // Clear whatever CSRF cookie has right now, force to generate a new one - ctx.Csrf.DeleteCookie(ctx) - - // Register last login - u.SetLastLogin() - - // update external user information - if err := externalaccount.UpdateExternalUser(ctx, u, gothUser, auth.SAML); err != nil { - if !errors.Is(err, util.ErrNotExist) { - log.Error("UpdateExternalUser failed: %v", err) - } - } - - if err := resetLocale(ctx, u); err != nil { - ctx.ServerError("resetLocale", err) - return - } - - if redirectTo := ctx.GetSiteCookie("redirect_to"); len(redirectTo) > 0 { - middleware.DeleteRedirectToCookie(ctx.Resp) - ctx.RedirectToFirst(redirectTo) - return - } - - ctx.Redirect(setting.AppSubURL + "/") -} - -func samlUserLoginCallback(ctx context.Context, authSource *auth.Source, request *http.Request, response http.ResponseWriter) (*user_model.User, goth.User, error) { - samlSource := authSource.Cfg.(*saml.Source) - - gothUser, err := samlSource.Callback(request, response) - if err != nil { - return nil, gothUser, err - } - - user := &user_model.User{ - LoginName: gothUser.UserID, - LoginType: auth.SAML, - LoginSource: authSource.ID, - } - - hasUser, err := user_model.GetUser(ctx, user) - if err != nil { - return nil, goth.User{}, err - } - - if hasUser { - return user, gothUser, nil - } - - // search in external linked users - externalLoginUser := &user_model.ExternalLoginUser{ - ExternalID: gothUser.UserID, - LoginSourceID: authSource.ID, - } - hasUser, err = user_model.GetExternalLogin(ctx, externalLoginUser) - if err != nil { - return nil, goth.User{}, err - } - if hasUser { - user, err = user_model.GetUserByID(request.Context(), externalLoginUser.UserID) - return user, gothUser, err - } - - // no user found to login - return nil, gothUser, nil -} - -func SAMLMetadata(ctx *context.Context) { - provider := ctx.Params(":provider") - loginSource, err := auth.GetActiveAuthSourceByName(ctx, provider, auth.SAML) - if err != nil || loginSource == nil { - ctx.NotFound("SAMLMetadata", err) - return - } - if err = loginSource.Cfg.(*saml.Source).Metadata(ctx.Req, ctx.Resp); err != nil { - ctx.ServerError("SAMLMetadata", err) - } -} diff --git a/routers/web/web.go b/routers/web/web.go index 5e18aac67d..a76b444e4f 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -667,11 +667,6 @@ func registerRoutes(m *web.Route) { m.Get("/{provider}", auth.SignInOAuth) m.Get("/{provider}/callback", auth.SignInOAuthCallback) }) - m.Group("/saml", func() { - m.Get("/{provider}", auth.SignInSAML) // redir to SAML IDP - m.Post("/{provider}/acs", auth.SignInSAMLCallback) - m.Get("/{provider}/metadata", auth.SAMLMetadata) - }) }) // ***** END: User ***** |