Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DISABLE_LOCAL_USER_MANAGEMENT mode added #18466

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
795b75e
Parameter DISABLE_LOCAL_USER_MANAGEMENT added
pboguslawski Oct 6, 2020
eca3563
DISABLE_LOCAL_USER_MANAGEMENT mode added
pboguslawski Oct 7, 2020
f92d339
Fixed external user syncing when local user management is disabled
pboguslawski Oct 7, 2020
70672ee
Hide message about changing username
pboguslawski Oct 7, 2020
d97a8ea
Fixed DISABLE_LOCAL_USER_MANAGEMENT mode
pboguslawski Oct 20, 2020
fe6ae27
Allow org name change in DISABLE_LOCAL_USER_MANAGEMENT mode
pboguslawski Mar 23, 2021
b3c084c
Merge master-IB#1105051 into main-IB#1105051
pboguslawski Jan 30, 2022
75e58fa
Merge main into main-IB#1105051
pboguslawski Jan 30, 2022
cda4a8a
Separate function for forced update added
pboguslawski Feb 1, 2022
15a3a5d
Merge main into main-IB#1105051
pboguslawski Feb 1, 2022
725a608
Merge remote-tracking branch 'main-IB#1105051' into main-IB#1105051
pboguslawski Feb 1, 2022
25673a9
Code cleanup
pboguslawski Feb 2, 2022
2b6990c
Merge remote-tracking branch 'main-IB#1105051' into main-IB#1105051
pboguslawski Feb 2, 2022
5c8f905
User data must be updatable from LDAP on authentication
pboguslawski Feb 3, 2022
2691234
Merge branch 'main-IB#1105051' of github.com:ibpl/gitea into main-IB#…
pboguslawski Feb 3, 2022
e45a831
Disable login prohibition and extra e-mail list
pboguslawski Feb 4, 2022
eaecead
Merge branch 'main-IB#1105051' of github.com:ibpl/gitea into main-IB#…
pboguslawski Feb 4, 2022
38e5a4d
Option hiding corrected
pboguslawski Feb 4, 2022
2c905e8
Merge branch 'main-IB#1105051' of github.com:ibpl/gitea into main-IB#…
pboguslawski Feb 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,9 @@ PATH =
;; Allow registration only using third-party services, it works only when DISABLE_REGISTRATION is false
;ALLOW_ONLY_EXTERNAL_REGISTRATION = false
;;
;; Disable local user management (i.e. when user data and password comes from LDAP and should not be changed locally in gitea).
;DISABLE_LOCAL_USER_MANAGEMENT = false
;;
;; User must sign in to view anything.
;REQUIRE_SIGNIN_VIEW = false
;;
Expand Down
1 change: 1 addition & 0 deletions docs/content/doc/advanced/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
- `ALLOW_ONLY_INTERNAL_REGISTRATION`: **false** Set to true to force registration only via Gitea.
- `ALLOW_ONLY_EXTERNAL_REGISTRATION`: **false** Set to true to force registration only using third-party services.
- `NO_REPLY_ADDRESS`: **noreply.DOMAIN** Value for the domain part of the user's email address in the Git log if user has set KeepEmailPrivate to true. DOMAIN resolves to the value in server.DOMAIN.
- `DISABLE_LOCAL_USER_MANAGEMENT`: **false** Set to true to disable local user management in gitea (i.e. when users are managed in LDAP).
The user's email will be replaced with a concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS.
- `USER_DELETE_WITH_COMMENTS_MAX_TIME`: **0** Minimum amount of time a user must exist before comments are kept when the user is deleted.
- `VALID_SITE_URL_SCHEMES`: **http, https**: Valid site url schemes for user profiles
Expand Down
52 changes: 49 additions & 3 deletions models/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,43 @@ func validateUser(u *User) error {
return ValidateEmail(u.Email)
}

// updateUserAllowed is used to block updating selected user fields when local user managemement is disabled.
func updateUserAllowed(u *User) error {
// Don't allow changes of selected user fields if local user management is disabled.
if setting.Service.DisableLocalUserManagement && u.Type == UserTypeIndividual {
if currUser, err := GetUserByID(u.ID); err == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More a nitpick: first check if err != nil to then return err so we can avoid a extra indent.

Copy link
Contributor Author

@pboguslawski pboguslawski Feb 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current syntax is ok (currUser is defined only for if scope).

if currUser.Name != u.Name {
return fmt.Errorf("cannot change user %s username; local user management disabled", u.Name)
}
if (currUser.LoginSource != u.LoginSource) || (currUser.LoginName != u.LoginName) {
return fmt.Errorf("cannot change user %s login; local user management disabled", u.Name)
}
if currUser.FullName != u.FullName {
return fmt.Errorf("cannot change user %s full name; local user management disabled", u.Name)
}
if currUser.Email != u.Email {
return fmt.Errorf("cannot change user %s e-mail; local user management disabled", u.Name)
}
if (currUser.Passwd != u.Passwd) || (currUser.PasswdHashAlgo != u.PasswdHashAlgo) {
return fmt.Errorf("cannot change user %s password; local user management disabled", u.Name)
}
if currUser.IsActive != u.IsActive {
return fmt.Errorf("cannot change user %s activity; local user management disabled", u.Name)
}
if currUser.IsAdmin != u.IsAdmin {
return fmt.Errorf("cannot change user %s admin permission; local user management disabled", u.Name)
}
} else {
return err
}
}
return nil
}

func updateUser(ctx context.Context, u *User, changePrimaryEmail bool) error {
if err := updateUserAllowed(u); err != nil {
return err
}
if err := validateUser(u); err != nil {
return err
}
Expand Down Expand Up @@ -873,15 +909,25 @@ func UpdateUser(u *User, emailChanged bool) error {

// UpdateUserCols update user according special columns
func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
return updateUserCols(db.GetEngine(ctx), u, cols...)
return updateUserCols(db.GetEngine(ctx), u, false, cols...)
}

// UpdateForceUserCols force update user according special columns.
func UpdateForceUserCols(ctx context.Context, u *User, cols ...string) error {
return updateUserCols(db.GetEngine(ctx), u, true, cols...)
}

// UpdateUserColsEngine update user according special columns
func UpdateUserColsEngine(e db.Engine, u *User, cols ...string) error {
return updateUserCols(e, u, cols...)
return updateUserCols(e, u, false, cols...)
}

func updateUserCols(e db.Engine, u *User, cols ...string) error {
func updateUserCols(e db.Engine, u *User, force bool, cols ...string) error {
if !force {
if err := updateUserAllowed(u); err != nil {
return err
}
}
if err := validateUser(u); err != nil {
return err
}
Expand Down
2 changes: 2 additions & 0 deletions modules/setting/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var Service = struct {
DisableRegistration bool
AllowOnlyInternalRegistration bool
AllowOnlyExternalRegistration bool
DisableLocalUserManagement bool
ShowRegistrationButton bool
ShowMilestonesDashboardPage bool
RequireSignInView bool
Expand Down Expand Up @@ -115,6 +116,7 @@ func newService() {
} else {
Service.RegisterManualConfirm = false
}
Service.DisableLocalUserManagement = sec.Key("DISABLE_LOCAL_USER_MANAGEMENT").MustBool()
Service.EmailDomainWhitelist = sec.Key("EMAIL_DOMAIN_WHITELIST").Strings(",")
Service.EmailDomainBlocklist = sec.Key("EMAIL_DOMAIN_BLOCKLIST").Strings(",")
Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration))
Expand Down
3 changes: 3 additions & 0 deletions modules/templates/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ func NewFuncMap() []template.FuncMap {
"DisableImportLocal": func() bool {
return !setting.ImportLocalPaths
},
"DisableLocalUserManagement": func() bool {
return setting.Service.DisableLocalUserManagement
},
"Dict": func(values ...interface{}) (map[string]interface{}, error) {
if len(values)%2 != 0 {
return nil, errors.New("invalid dict call")
Expand Down
30 changes: 30 additions & 0 deletions routers/web/admin/auths.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ func Authentications(ctx *context.Context) {
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminAuthentications"] = true

// No access to this page if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("Authentications", fmt.Errorf("access to Authentications function denied; local user management disabled"))
return
}

var err error
ctx.Data["Sources"], err = auth.Sources()
if err != nil {
Expand Down Expand Up @@ -111,6 +117,12 @@ func NewAuthSource(ctx *context.Context) {
ctx.Data["SSPISeparatorReplacement"] = "_"
ctx.Data["SSPIDefaultLanguage"] = ""

// No access to this page if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("NewAuthSource", fmt.Errorf("access to NewAuthSource function denied; local user management disabled"))
return
}

// only the first as default
ctx.Data["oauth2_provider"] = oauth2providers[0]

Expand Down Expand Up @@ -240,6 +252,12 @@ func NewAuthSourcePost(ctx *context.Context) {
ctx.Data["SSPISeparatorReplacement"] = "_"
ctx.Data["SSPIDefaultLanguage"] = ""

// Don't allow to create auth source if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("NewAuthSourcePost", fmt.Errorf("cannot create auth source; local user management disabled"))
return
}

hasTLS := false
var config convert.Conversion
switch auth.Type(form.Type) {
Expand Down Expand Up @@ -314,6 +332,12 @@ func EditAuthSource(ctx *context.Context) {
oauth2providers := oauth2.GetOAuth2Providers()
ctx.Data["OAuth2Providers"] = oauth2providers

// No access to this page if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("EditAuthSource", fmt.Errorf("access to EditAuthSource page denied; local user management disabled"))
return
}

source, err := auth.GetSourceByID(ctx.ParamsInt64(":authid"))
if err != nil {
ctx.ServerError("auth.GetSourceByID", err)
Expand Down Expand Up @@ -349,6 +373,12 @@ func EditAuthSourcePost(ctx *context.Context) {
oauth2providers := oauth2.GetOAuth2Providers()
ctx.Data["OAuth2Providers"] = oauth2providers

// Don't allow to update auth source if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("EditAuthSourcePost", fmt.Errorf("cannot update auth source; local user management disabled"))
return
}

source, err := auth.GetSourceByID(ctx.ParamsInt64(":authid"))
if err != nil {
ctx.ServerError("auth.GetSourceByID", err)
Expand Down
13 changes: 13 additions & 0 deletions routers/web/admin/emails.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package admin

import (
"bytes"
"fmt"
"net/http"
"net/url"

Expand All @@ -28,6 +29,12 @@ func Emails(ctx *context.Context) {
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminEmails"] = true

// No access to this page if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("Emails", fmt.Errorf("access to Emails function denied; local user management disabled"))
return
}

opts := &user_model.SearchEmailOptions{
ListOptions: db.ListOptions{
PageSize: setting.UI.Admin.UserPagingNum,
Expand Down Expand Up @@ -109,6 +116,12 @@ func isKeywordValid(keyword string) bool {

// ActivateEmail serves a POST request for activating/deactivating a user's email
func ActivateEmail(ctx *context.Context) {
// Don't allow to activate/deactivate emails if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("ActivateEmail", fmt.Errorf("cannot activate email; local user management disabled"))
return
}

truefalse := map[string]bool{"1": true, "0": false}

uid := ctx.FormInt64("uid")
Expand Down
19 changes: 19 additions & 0 deletions routers/web/admin/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package admin

import (
"fmt"
"net/http"
"net/url"
"strconv"
Expand Down Expand Up @@ -81,6 +82,12 @@ func NewUser(ctx *context.Context) {

ctx.Data["login_type"] = "0-0"

// No access to this page if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("NewUser", fmt.Errorf("access to NewUser function denied; local user management disabled"))
return
}

sources, err := auth.Sources()
if err != nil {
ctx.ServerError("auth.Sources", err)
Expand All @@ -100,6 +107,11 @@ func NewUserPost(ctx *context.Context) {
ctx.Data["PageIsAdminUsers"] = true
ctx.Data["DefaultUserVisibilityMode"] = setting.Service.DefaultUserVisibilityMode

if setting.Service.DisableLocalUserManagement {
ctx.ServerError("NewUserPost", fmt.Errorf("cannot create new user; local user management disabled"))
return
}

sources, err := auth.Sources()
if err != nil {
ctx.ServerError("auth.Sources", err)
Expand Down Expand Up @@ -278,6 +290,13 @@ func EditUserPost(ctx *context.Context) {

if len(form.Password) > 0 && (u.IsLocal() || u.IsOAuth2()) {
var err error

// Don't allow password changes if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("UpdateUser", fmt.Errorf("cannot change %s password; local user management disabled", u.Name))
return
}

if len(form.Password) < setting.MinPasswordLength {
ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserEdit, &form)
Expand Down
29 changes: 29 additions & 0 deletions routers/web/user/setting/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package setting

import (
"errors"
"fmt"
"net/http"
"time"

Expand Down Expand Up @@ -94,6 +95,11 @@ func EmailPost(ctx *context.Context) {

// Make emailaddress primary.
if ctx.FormString("_method") == "PRIMARY" {
// No access to this function if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("MakeEmailPrimary", fmt.Errorf("access to MakeEmailPrimary function denied; local user management disabled"))
return
}
if err := user_model.MakeEmailPrimary(&user_model.EmailAddress{ID: ctx.FormInt64("id")}); err != nil {
ctx.ServerError("MakeEmailPrimary", err)
return
Expand All @@ -105,6 +111,11 @@ func EmailPost(ctx *context.Context) {
}
// Send activation Email
if ctx.FormString("_method") == "SENDACTIVATION" {
// No access to this function if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("SendActivation", fmt.Errorf("access to SendActivation function denied; local user management disabled"))
return
}
var address string
if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) {
log.Error("Send activation: activation still pending")
Expand Down Expand Up @@ -170,6 +181,12 @@ func EmailPost(ctx *context.Context) {
return
}

// No access to this function if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("AddEmailAddress", fmt.Errorf("access to AddEmailAddress function denied; local user management disabled"))
return
}

if ctx.HasError() {
loadAccountData(ctx)

Expand Down Expand Up @@ -215,6 +232,12 @@ func EmailPost(ctx *context.Context) {

// DeleteEmail response for delete user's email
func DeleteEmail(ctx *context.Context) {
// No access to this function if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("DeleteEmail", fmt.Errorf("access to DeleteEmail function denied; local user management disabled"))
return
}

if err := user_model.DeleteEmailAddress(&user_model.EmailAddress{ID: ctx.FormInt64("id"), UID: ctx.User.ID}); err != nil {
ctx.ServerError("DeleteEmail", err)
return
Expand All @@ -229,6 +252,12 @@ func DeleteEmail(ctx *context.Context) {

// DeleteAccount render user suicide page and response for delete user himself
func DeleteAccount(ctx *context.Context) {
// No access to this page if local user management is disabled.
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("DeleteAccount", fmt.Errorf("access to DeleteAccount function denied; local user management disabled"))
return
}

ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsAccount"] = true

Expand Down
3 changes: 3 additions & 0 deletions routers/web/user/setting/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ func HandleUsernameChange(ctx *context.Context, user *user_model.User, newName s

// Check if user name has been changed
if user.LowerName != strings.ToLower(newName) {
if setting.Service.DisableLocalUserManagement {
ctx.ServerError("ChangeUserName", fmt.Errorf("cannot change user %s username; local user management disabled", user.Name))
}
if err := user_model.ChangeUserName(user, newName); err != nil {
switch {
case user_model.IsErrUserAlreadyExist(err):
Expand Down
10 changes: 8 additions & 2 deletions services/auth/source/ldap/source_authenticate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/mailer"
user_service "code.gitea.io/gitea/services/user"
)
Expand All @@ -37,7 +38,7 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
return nil, err
}
}
if user != nil && !user.ProhibitLogin {
if user != nil && (!user.ProhibitLogin || setting.Service.DisableLocalUserManagement) {
cols := make([]string, 0)
if len(source.AdminFilter) > 0 && user.IsAdmin != sr.IsAdmin {
// Change existing admin flag only if AdminFilter option is set
Expand All @@ -49,8 +50,13 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
user.IsRestricted = sr.IsRestricted
cols = append(cols, "is_restricted")
}
if user.ProhibitLogin && setting.Service.DisableLocalUserManagement {
// When local user management is disabled, active user is allowed to login.
user.ProhibitLogin = false
cols = append(cols, "prohibit_login")
}
if len(cols) > 0 {
err = user_model.UpdateUserCols(db.DefaultContext, user, cols...)
err = user_model.UpdateForceUserCols(db.DefaultContext, user, cols...)
if err != nil {
return nil, err
}
Expand Down
Loading