Procházet zdrojové kódy

conf: overhaul auth and user settings (#5942)

* conf: overhaul auth and user settings

* ci: update travis Go versions
ᴜɴᴋɴᴡᴏɴ před 4 roky
rodič
revize
7950f2d17d

+ 1 - 1
.travis.yml

@@ -1,8 +1,8 @@
 os: linux
 language: go
 go:
-  - 1.12.x
   - 1.13.x
+  - 1.14.x
 go_import_path: gogs.io/gogs
 
 env:

+ 6 - 0
CHANGELOG.md

@@ -22,7 +22,13 @@ All notable changes to Gogs are documented in this file.
 - Configuration option `[server] LANDING_PAGE` is deprecated and will end support in 0.13.0, please start using `[server] LANDING_URL`.
 - Configuration option `[database] DB_TYPE` is deprecated and will end support in 0.13.0, please start using `[database] TYPE`.
 - Configuration option `[database] PASSWD` is deprecated and will end support in 0.13.0, please start using `[database] PASSWORD`.
+- Configuration option `[security] REVERSE_PROXY_AUTHENTICATION_USER` is deprecated and will end support in 0.13.0, please start using `[auth] REVERSE_PROXY_AUTHENTICATION_HEADER`.
 - Configuration section `[mailer]` is deprecated and will end support in 0.13.0, please start using `[email]`.
+- Configuration section `[service]` is deprecated and will end support in 0.13.0, please start using `[auth]`.
+- Configuration option `[auth] ACTIVE_CODE_LIVE_MINUTES` is deprecated and will end support in 0.13.0, please start using `[auth] ACTIVATE_CODE_LIVES`.
+- Configuration option `[auth] RESET_PASSWD_CODE_LIVE_MINUTES` is deprecated and will end support in 0.13.0, please start using `[auth] RESET_PASSWORD_CODE_LIVES`.
+- Configuration option `[auth] ENABLE_CAPTCHA` is deprecated and will end support in 0.13.0, please start using `[auth] ENABLE_REGISTRATION_CAPTCHA`.
+- Configuration option `[auth] ENABLE_NOTIFY_MAIL` is deprecated and will end support in 0.13.0, please start using `[user] ENABLE_EMAIL_NOTIFICATION`.
 
 ### Fixed
 

+ 26 - 19
conf/app.ini

@@ -160,8 +160,6 @@ COOKIE_REMEMBER_NAME = gogs_incredible
 COOKIE_USERNAME = gogs_awesome
 ; Whether to set secure cookie.
 COOKIE_SECURE = false
-; The HTTP header for reverse proxy authentication via username.
-REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
 ; Whether to set cookie to indicate user login status.
 ENABLE_LOGIN_STATUS_COOKIE = false
 ; The cookie name to store user login status.
@@ -201,6 +199,32 @@ USE_PLAIN_TEXT = false
 ; It is used to support older mail clients and make spam filters happier.
 ADD_PLAIN_TEXT_ALT = false
 
+[auth]
+; The valid duration of activate code in minutes.
+ACTIVATE_CODE_LIVES = 180
+; The valid duration of reset password code in minutes.
+RESET_PASSWORD_CODE_LIVES = 180
+; Whether to require email confirmation for adding new email addresses.
+; Enable this option will also require user to confirm the email for registration.
+REQUIRE_EMAIL_CONFIRMATION = false
+; Whether to disallow anonymous users visiting the site.
+REQUIRE_SIGNIN_VIEW = false
+; Whether to disable self-registration. When disabled, accounts would have to be created by admins.
+DISABLE_REGISTRATION = false
+; Whether to enable captcha validation for registration
+ENABLE_REGISTRATION_CAPTCHA = true
+
+; Whether to enable reverse proxy authentication via HTTP header.
+ENABLE_REVERSE_PROXY_AUTHENTICATION = false
+; Whether to automatically create new users for reverse proxy authentication.
+ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
+; The HTTP header used as username for reverse proxy authentication.
+REVERSE_PROXY_AUTHENTICATION_HEADER = X-WEBAUTH-USER
+
+[user]
+; Whether to enable email notifications for users.
+ENABLE_EMAIL_NOTIFICATION = false
+
 ; Attachment settings for releases
 [release.attachment]
 ; Whether attachments are enabled. Defaults to `true`
@@ -239,23 +263,6 @@ ACCESS_CONTROL_ALLOW_ORIGIN =
 ; Disable regular (non-admin) users to create organizations
 DISABLE_REGULAR_ORG_CREATION = false
 
-[service]
-ACTIVE_CODE_LIVE_MINUTES = 180
-RESET_PASSWD_CODE_LIVE_MINUTES = 180
-; User need to confirm e-mail for registration
-REGISTER_EMAIL_CONFIRM = false
-; Does not allow register and admin create account only
-DISABLE_REGISTRATION = false
-; User must sign in to view anything.
-REQUIRE_SIGNIN_VIEW = false
-; Mail notification
-ENABLE_NOTIFY_MAIL = false
-; More detail: https://github.com/gogits/gogs/issues/165
-ENABLE_REVERSE_PROXY_AUTHENTICATION = false
-ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
-; Enable captcha validation for registration
-ENABLE_CAPTCHA = true
-
 [webhook]
 ; Types are enabled for users to use, can be "gogs", "slack", "discord", "dingtalk"
 TYPES = gogs, slack, discord, dingtalk

+ 14 - 10
conf/locale/locale_en-US.ini

@@ -1253,21 +1253,25 @@ config.email.send_test_mail = Send test email
 config.email.test_mail_failed = Failed to send test email to '%s': %v
 config.email.test_mail_sent = Test email has been sent to '%s'.
 
+config.auth_config = Authentication configuration
+config.auth.activate_code_lives = Activate code lives
+config.auth.reset_password_code_lives = Reset password code lives
+config.auth.require_email_confirm = Require email confirmation
+config.auth.require_sign_in_view = Require sign in view
+config.auth.disable_registration = Disable registration
+config.auth.enable_registration_captcha = Enable registration captcha
+config.auth.enable_reverse_proxy_authentication = Enable reverse proxy authentication
+config.auth.enable_reverse_proxy_auto_registration = Enable reverse proxy auto registration
+config.auth.reverse_proxy_authentication_header = Reverse proxy authentication header
+
+config.user_config = User configuration
+config.user.enable_email_notify = Enable email notification
+
 config.log_file_root_path = Log File Root Path
 
 config.http_config = HTTP Configuration
 config.http_access_control_allow_origin = Access Control Allow Origin
 
-config.service_config = Service Configuration
-config.register_email_confirm = Require Email Confirmation
-config.disable_register = Disable Registration
-config.show_registration_button = Show Register Button
-config.require_sign_in_view = Require Sign In View
-config.mail_notify = Mail Notification
-config.disable_key_size_check = Disable Minimum Key Size Check
-config.enable_captcha = Enable Captcha
-config.active_code_lives = Active Code Lives
-config.reset_password_code_lives = Reset Password Code Lives
 
 config.webhook_config = Webhook Configuration
 config.queue_length = Queue Length

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 4 - 4
internal/assets/conf/conf_gen.go


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 3
internal/assets/templates/templates_gen.go


+ 2 - 2
internal/auth/auth.go

@@ -90,7 +90,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (_ *db.User, isBasic
 	uid, isTokenAuth := SignedInID(ctx, sess)
 
 	if uid <= 0 {
-		if conf.Service.EnableReverseProxyAuth {
+		if conf.Auth.EnableReverseProxyAuthentication {
 			webAuthUser := ctx.Req.Header.Get(conf.Security.ReverseProxyAuthenticationUser)
 			if len(webAuthUser) > 0 {
 				u, err := db.GetUserByName(webAuthUser)
@@ -101,7 +101,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (_ *db.User, isBasic
 					}
 
 					// Check if enabled auto-registration.
-					if conf.Service.EnableReverseProxyAutoRegister {
+					if conf.Auth.EnableReverseProxyAutoRegistration {
 						u := &db.User{
 							Name:     webAuthUser,
 							Email:    gouuid.NewV4().String() + "@localhost",

+ 1 - 2
internal/cmd/hook.go

@@ -23,8 +23,8 @@ import (
 	"gogs.io/gogs/internal/conf"
 	"gogs.io/gogs/internal/db"
 	"gogs.io/gogs/internal/db/errors"
-	"gogs.io/gogs/internal/httplib"
 	"gogs.io/gogs/internal/email"
+	"gogs.io/gogs/internal/httplib"
 	"gogs.io/gogs/internal/template"
 )
 
@@ -198,7 +198,6 @@ func runHookPostReceive(c *cli.Context) error {
 
 	// Post-receive hook does more than just gather Git information,
 	// so we need to setup additional services for email notifications.
-	conf.NewPostReceiveHookServices()
 	email.NewContext()
 
 	isWiki := strings.Contains(os.Getenv(db.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/")

+ 4 - 5
internal/cmd/serv.go

@@ -220,12 +220,11 @@ func runServ(c *cli.Context) error {
 			}
 		}
 	} else {
-		conf.NewService()
 		// Check if the key can access to the repository in case of it is a deploy key (a deploy keys != user key).
-		// A deploy key doesn't represent a signed in user, so in a site with Service.RequireSignInView activated
-		// we should give read access only in repositories where this deploy key is in use. In other case, a server
-		// or system using an active deploy key can get read access to all the repositories in a Gogs service.
-		if key.IsDeployKey() && conf.Service.RequireSignInView {
+		// A deploy key doesn't represent a signed in user, so in a site with Auth.RequireSignInView enabled,
+		// we should give read access only in repositories where this deploy key is in use. In other cases,
+		// a server or system using an active deploy key can get read access to all repositories on a Gogs instace.
+		if key.IsDeployKey() && conf.Auth.RequireSigninView {
 			checkDeployKey(key, repo)
 		}
 	}

+ 1 - 1
internal/cmd/web.go

@@ -171,7 +171,7 @@ func runWeb(c *cli.Context) error {
 	m := newMacaron()
 
 	reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true})
-	ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: conf.Service.RequireSignInView})
+	ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: conf.Auth.RequireSigninView})
 	ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true})
 	reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true})
 

+ 23 - 68
internal/conf/conf.go

@@ -61,6 +61,8 @@ var File *ini.File
 // It is safe to call this function multiple times with desired `customConf`, but it is
 // not concurrent safe.
 //
+// NOTE: The order of loading configuration sections matters as one may depend on another.
+//
 // ⚠️ WARNING: Do not print anything in this function other than wanrings.
 func Init(customConf string) error {
 	var err error
@@ -232,6 +234,26 @@ func Init(customConf string) error {
 		Email.FromEmail = parsed.Address
 	}
 
+	// ***********************************
+	// ----- Authentication settings -----
+	// ***********************************
+
+	if err = File.Section("auth").MapTo(&Auth); err != nil {
+		return errors.Wrap(err, "mapping [auth] section")
+	}
+	// LEGACY [0.13]: In case there are values with old section name.
+	if err = File.Section("service").MapTo(&Auth); err != nil {
+		return errors.Wrap(err, "mapping [service] section")
+	}
+
+	// ***********************************
+	// ----- User settings -----
+	// ***********************************
+
+	if err = File.Section("user").MapTo(&User); err != nil {
+		return errors.Wrap(err, "mapping [user] section")
+	}
+
 	handleDeprecated()
 
 	// TODO
@@ -659,31 +681,6 @@ func InitLogging() {
 	}
 }
 
-var Service struct {
-	ActiveCodeLives                int
-	ResetPwdCodeLives              int
-	RegisterEmailConfirm           bool
-	DisableRegistration            bool
-	ShowRegistrationButton         bool
-	RequireSignInView              bool
-	EnableNotifyMail               bool
-	EnableReverseProxyAuth         bool
-	EnableReverseProxyAutoRegister bool
-	EnableCaptcha                  bool
-}
-
-func newService() {
-	sec := File.Section("service")
-	Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180)
-	Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180)
-	Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool()
-	Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration)
-	Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
-	Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
-	Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
-	Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool()
-}
-
 func newCacheService() {
 	CacheAdapter = File.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
 	switch CacheAdapter {
@@ -713,53 +710,11 @@ func newSessionService() {
 	log.Trace("Session service is enabled")
 }
 
-func newRegisterMailService() {
-	if !File.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() {
-		return
-	} else if !Email.Enabled {
-		log.Warn("Email confirmation is not enabled due to the mail service is not available")
-		return
-	}
-	Service.RegisterEmailConfirm = true
-	log.Trace("Email confirmation is enabled")
-}
-
-// newNotifyMailService initializes notification email service options from configuration.
-// No non-error log will be printed in hook mode.
-func newNotifyMailService() {
-	if !File.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
-		return
-	} else if !Email.Enabled {
-		log.Warn("Email notification is not enabled due to the mail service is not available")
-		return
-	}
-	Service.EnableNotifyMail = true
-
-	if HookMode {
-		return
-	}
-	log.Trace("Email notification is enabled")
-}
-
-func NewService() {
-	newService()
-}
-
 func NewServices() {
-	newService()
 	newCacheService()
 	newSessionService()
-	newRegisterMailService()
-	newNotifyMailService()
 }
 
 // HookMode indicates whether program starts as Git server-side hook callback.
+// All operations should be done synchronously to prevent program exits before finishing.
 var HookMode bool
-
-// NewPostReceiveHookServices initializes all services that are needed by
-// Git server-side post-receive hook callback.
-func NewPostReceiveHookServices() {
-	HookMode = true
-	newService()
-	newNotifyMailService()
-}

+ 66 - 8
internal/conf/static.go

@@ -142,15 +142,17 @@ var (
 
 	// Security settings
 	Security struct {
-		InstallLock                    bool
-		SecretKey                      string
-		LoginRememberDays              int
-		CookieRememberName             string
-		CookieUsername                 string
-		CookieSecure                   bool
+		InstallLock             bool
+		SecretKey               string
+		LoginRememberDays       int
+		CookieRememberName      string
+		CookieUsername          string
+		CookieSecure            bool
+		EnableLoginStatusCookie bool
+		LoginStatusCookieName   string
+
+		// Deprecated: Use Auth.ReverseProxyAuthenticationHeader instead, will be removed in 0.13.
 		ReverseProxyAuthenticationUser string
-		EnableLoginStatusCookie        bool
-		LoginStatusCookieName          string
 	}
 
 	// Email settings
@@ -179,6 +181,36 @@ var (
 		// Deprecated: Use Password instead, will be removed in 0.13.
 		Passwd string
 	}
+
+	// Authentication settings
+	Auth struct {
+		ActivateCodeLives         int
+		ResetPasswordCodeLives    int
+		RequireEmailConfirmation  bool
+		RequireSigninView         bool
+		DisableRegistration       bool
+		EnableRegistrationCaptcha bool
+
+		EnableReverseProxyAuthentication   bool
+		EnableReverseProxyAutoRegistration bool
+		ReverseProxyAuthenticationHeader   string
+
+		// Deprecated: Use ActivateCodeLives instead, will be removed in 0.13.
+		ActiveCodeLiveMinutes int
+		// Deprecated: Use ResetPasswordCodeLives instead, will be removed in 0.13.
+		ResetPasswdCodeLiveMinutes int
+		// Deprecated: Use RequireEmailConfirmation instead, will be removed in 0.13.
+		RegisterEmailConfirm bool
+		// Deprecated: Use EnableRegistrationCaptcha instead, will be removed in 0.13.
+		EnableCaptcha bool
+		// Deprecated: Use User.EnableEmailNotification instead, will be removed in 0.13.
+		EnableNotifyMail bool
+	}
+
+	// User settings
+	User struct {
+		EnableEmailNotification bool
+	}
 )
 
 // handleDeprecated transfers deprecated values to the new ones when set.
@@ -210,4 +242,30 @@ func handleDeprecated() {
 		Email.Password = Email.Passwd
 		Email.Passwd = ""
 	}
+
+	if Auth.ActiveCodeLiveMinutes > 0 {
+		Auth.ActivateCodeLives = Auth.ActiveCodeLiveMinutes
+		Auth.ActiveCodeLiveMinutes = 0
+	}
+	if Auth.ResetPasswdCodeLiveMinutes > 0 {
+		Auth.ResetPasswordCodeLives = Auth.ResetPasswdCodeLiveMinutes
+		Auth.ResetPasswdCodeLiveMinutes = 0
+	}
+	if Auth.RegisterEmailConfirm {
+		Auth.RequireEmailConfirmation = true
+		Auth.RegisterEmailConfirm = false
+	}
+	if Auth.EnableCaptcha {
+		Auth.EnableRegistrationCaptcha = true
+		Auth.EnableCaptcha = false
+	}
+	if Security.ReverseProxyAuthenticationUser != "" {
+		Auth.ReverseProxyAuthenticationHeader = Security.ReverseProxyAuthenticationUser
+		Security.ReverseProxyAuthenticationUser = ""
+	}
+
+	if Auth.EnableNotifyMail {
+		User.EnableEmailNotification = true
+		Auth.EnableNotifyMail = false
+	}
 }

+ 1 - 1
internal/context/auth.go

@@ -71,7 +71,7 @@ func Toggle(options *ToggleOptions) macaron.Handler {
 				c.SetCookie("redirect_to", url.QueryEscape(conf.Server.Subpath+c.Req.RequestURI), 0, conf.Server.Subpath)
 				c.Redirect(conf.Server.Subpath + "/user/login")
 				return
-			} else if !c.User.IsActive && conf.Service.RegisterEmailConfirm {
+			} else if !c.User.IsActive && conf.Auth.RequireEmailConfirmation {
 				c.Data["Title"] = c.Tr("auth.active_your_account")
 				c.HTML(200, "user/auth/activate")
 				return

+ 1 - 1
internal/context/context.go

@@ -323,7 +323,7 @@ func Contexter() macaron.Handler {
 		log.Trace("Session ID: %s", sess.ID())
 		log.Trace("CSRF Token: %v", c.Data["CSRFToken"])
 
-		c.Data["ShowRegistrationButton"] = conf.Service.ShowRegistrationButton
+		c.Data["ShowRegistrationButton"] = !conf.Auth.DisableRegistration
 		c.Data["ShowFooterBranding"] = conf.ShowFooterBranding
 
 		c.renderNoticeBanner()

+ 2 - 2
internal/db/issue_mail.go

@@ -10,9 +10,9 @@ import (
 	"github.com/unknwon/com"
 	log "unknwon.dev/clog/v2"
 
+	"gogs.io/gogs/internal/conf"
 	"gogs.io/gogs/internal/email"
 	"gogs.io/gogs/internal/markup"
-	"gogs.io/gogs/internal/conf"
 )
 
 func (issue *Issue) MailSubject() string {
@@ -95,7 +95,7 @@ func NewMailerIssue(issue *Issue) email.Issue {
 // 1. Repository watchers, users who participated in comments and the assignee.
 // 2. Users who are not in 1. but get mentioned in current issue/comment.
 func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string) error {
-	if !conf.Service.EnableNotifyMail {
+	if !conf.User.EnableEmailNotification {
 		return nil
 	}
 

+ 3 - 3
internal/db/user.go

@@ -202,7 +202,7 @@ func (u *User) HTMLURL() string {
 func (u *User) GenerateEmailActivateCode(email string) string {
 	code := tool.CreateTimeLimitCode(
 		com.ToStr(u.ID)+email+u.LowerName+u.Passwd+u.Rands,
-		conf.Service.ActiveCodeLives, nil)
+		conf.Auth.ActivateCodeLives, nil)
 
 	// Add tail hex username
 	code += hex.EncodeToString([]byte(u.LowerName))
@@ -617,7 +617,7 @@ func parseUserFromCode(code string) (user *User) {
 
 // verify active code when active account
 func VerifyUserActiveCode(code string) (user *User) {
-	minutes := conf.Service.ActiveCodeLives
+	minutes := conf.Auth.ActivateCodeLives
 
 	if user = parseUserFromCode(code); user != nil {
 		// time limit code
@@ -633,7 +633,7 @@ func VerifyUserActiveCode(code string) (user *User) {
 
 // verify active code when active account
 func VerifyActiveEmailCode(code, email string) *EmailAddress {
-	minutes := conf.Service.ActiveCodeLives
+	minutes := conf.Auth.ActivateCodeLives
 
 	if user := parseUserFromCode(code); user != nil {
 		// time limit code

+ 3 - 3
internal/email/email.go

@@ -105,8 +105,8 @@ type Issue interface {
 func SendUserMail(c *macaron.Context, u User, tpl, code, subject, info string) {
 	data := map[string]interface{}{
 		"Username":          u.DisplayName(),
-		"ActiveCodeLives":   conf.Service.ActiveCodeLives / 60,
-		"ResetPwdCodeLives": conf.Service.ResetPwdCodeLives / 60,
+		"ActiveCodeLives":   conf.Auth.ActivateCodeLives / 60,
+		"ResetPwdCodeLives": conf.Auth.ResetPasswordCodeLives / 60,
 		"Code":              code,
 	}
 	body, err := render(tpl, data)
@@ -133,7 +133,7 @@ func SendResetPasswordMail(c *macaron.Context, u User) {
 func SendActivateEmailMail(c *macaron.Context, u User, email string) {
 	data := map[string]interface{}{
 		"Username":        u.DisplayName(),
-		"ActiveCodeLives": conf.Service.ActiveCodeLives / 60,
+		"ActiveCodeLives": conf.Auth.ActivateCodeLives / 60,
 		"Code":            u.GenerateEmailActivateCode(email),
 		"Email":           email,
 	}

+ 2 - 1
internal/route/admin/admin.go

@@ -203,12 +203,13 @@ func Config(c *context.Context) {
 	c.Data["Database"] = conf.Database
 	c.Data["Security"] = conf.Security
 	c.Data["Email"] = conf.Email
+	c.Data["Auth"] = conf.Auth
+	c.Data["User"] = conf.User
 
 	c.Data["LogRootPath"] = conf.LogRootPath
 
 	c.Data["HTTP"] = conf.HTTP
 
-	c.Data["Service"] = conf.Service
 	c.Data["Webhook"] = conf.Webhook
 
 	c.Data["CacheAdapter"] = conf.CacheAdapter

+ 2 - 2
internal/route/api/v1/user/email.go

@@ -10,9 +10,9 @@ import (
 
 	api "github.com/gogs/go-gogs-client"
 
+	"gogs.io/gogs/internal/conf"
 	"gogs.io/gogs/internal/context"
 	"gogs.io/gogs/internal/db"
-	"gogs.io/gogs/internal/conf"
 )
 
 func ListEmails(c *context.APIContext) {
@@ -39,7 +39,7 @@ func AddEmail(c *context.APIContext, form api.CreateEmailOption) {
 		emails[i] = &db.EmailAddress{
 			UID:         c.User.ID,
 			Email:       form.Emails[i],
-			IsActivated: !conf.Service.RegisterEmailConfirm,
+			IsActivated: !conf.Auth.RequireEmailConfirmation,
 		}
 	}
 

+ 2 - 2
internal/route/dev/template.go

@@ -16,8 +16,8 @@ func TemplatePreview(c *context.Context) {
 	c.Data["AppVersion"] = conf.App.Version
 	c.Data["AppURL"] = conf.Server.ExternalURL
 	c.Data["Code"] = "2014031910370000009fff6782aadb2162b4a997acb69d4400888e0b9274657374"
-	c.Data["ActiveCodeLives"] = conf.Service.ActiveCodeLives / 60
-	c.Data["ResetPwdCodeLives"] = conf.Service.ResetPwdCodeLives / 60
+	c.Data["ActiveCodeLives"] = conf.Auth.ActivateCodeLives / 60
+	c.Data["ResetPwdCodeLives"] = conf.Auth.ResetPasswordCodeLives / 60
 	c.Data["CurDbValue"] = ""
 
 	c.HTML(200, (c.Params("*")))

+ 1 - 1
internal/route/home.go

@@ -22,7 +22,7 @@ const (
 
 func Home(c *context.Context) {
 	if c.IsLogged {
-		if !c.User.IsActive && conf.Service.RegisterEmailConfirm {
+		if !c.User.IsActive && conf.Auth.RequireEmailConfirmation {
 			c.Data["Title"] = c.Tr("auth.active_your_account")
 			c.Success(user2.ACTIVATE)
 		} else {

+ 5 - 5
internal/route/install.go

@@ -180,16 +180,16 @@ func Install(c *context.Context) {
 		f.SMTPFrom = conf.Email.From
 		f.SMTPUser = conf.Email.User
 	}
-	f.RegisterConfirm = conf.Service.RegisterEmailConfirm
-	f.MailNotify = conf.Service.EnableNotifyMail
+	f.RegisterConfirm = conf.Auth.RequireEmailConfirmation
+	f.MailNotify = conf.User.EnableEmailNotification
 
 	// Server and other services settings
 	f.OfflineMode = conf.Server.OfflineMode
 	f.DisableGravatar = conf.DisableGravatar
 	f.EnableFederatedAvatar = conf.EnableFederatedAvatar
-	f.DisableRegistration = conf.Service.DisableRegistration
-	f.EnableCaptcha = conf.Service.EnableCaptcha
-	f.RequireSignInView = conf.Service.RequireSignInView
+	f.DisableRegistration = conf.Auth.DisableRegistration
+	f.EnableCaptcha = conf.Auth.EnableRegistrationCaptcha
+	f.RequireSignInView = conf.Auth.RequireSigninView
 
 	form.Assign(f, c.Data)
 	c.Success(INSTALL)

+ 1 - 1
internal/route/repo/http.go

@@ -77,7 +77,7 @@ func HTTPContexter() macaron.Handler {
 		}
 
 		// Authentication is not required for pulling from public repositories.
-		if isPull && !repo.IsPrivate && !conf.Service.RequireSignInView {
+		if isPull && !repo.IsPrivate && !conf.Auth.RequireSigninView {
 			c.Map(&HTTPContext{
 				Context: c,
 			})

+ 2 - 2
internal/route/repo/setting.go

@@ -18,8 +18,8 @@ import (
 	"gogs.io/gogs/internal/context"
 	"gogs.io/gogs/internal/db"
 	"gogs.io/gogs/internal/db/errors"
-	"gogs.io/gogs/internal/form"
 	"gogs.io/gogs/internal/email"
+	"gogs.io/gogs/internal/form"
 	"gogs.io/gogs/internal/tool"
 )
 
@@ -398,7 +398,7 @@ func SettingsCollaborationPost(c *context.Context) {
 		return
 	}
 
-	if conf.Service.EnableNotifyMail {
+	if conf.User.EnableEmailNotification {
 		email.SendCollaboratorMail(db.NewMailerUser(u), db.NewMailerUser(c.User), db.NewMailerRepo(c.Repo.Repository))
 	}
 

+ 12 - 12
internal/route/user/auth.go

@@ -292,9 +292,9 @@ func SignOut(c *context.Context) {
 func SignUp(c *context.Context) {
 	c.Title("sign_up")
 
-	c.Data["EnableCaptcha"] = conf.Service.EnableCaptcha
+	c.Data["EnableCaptcha"] = conf.Auth.EnableRegistrationCaptcha
 
-	if conf.Service.DisableRegistration {
+	if conf.Auth.DisableRegistration {
 		c.Data["DisableRegistration"] = true
 		c.Success(SIGNUP)
 		return
@@ -306,9 +306,9 @@ func SignUp(c *context.Context) {
 func SignUpPost(c *context.Context, cpt *captcha.Captcha, f form.Register) {
 	c.Title("sign_up")
 
-	c.Data["EnableCaptcha"] = conf.Service.EnableCaptcha
+	c.Data["EnableCaptcha"] = conf.Auth.EnableRegistrationCaptcha
 
-	if conf.Service.DisableRegistration {
+	if conf.Auth.DisableRegistration {
 		c.Status(403)
 		return
 	}
@@ -318,7 +318,7 @@ func SignUpPost(c *context.Context, cpt *captcha.Captcha, f form.Register) {
 		return
 	}
 
-	if conf.Service.EnableCaptcha && !cpt.VerifyReq(c.Req) {
+	if conf.Auth.EnableRegistrationCaptcha && !cpt.VerifyReq(c.Req) {
 		c.FormErr("Captcha")
 		c.RenderWithErr(c.Tr("form.captcha_incorrect"), SIGNUP, &f)
 		return
@@ -334,7 +334,7 @@ func SignUpPost(c *context.Context, cpt *captcha.Captcha, f form.Register) {
 		Name:     f.UserName,
 		Email:    f.Email,
 		Passwd:   f.Password,
-		IsActive: !conf.Service.RegisterEmailConfirm,
+		IsActive: !conf.Auth.RequireEmailConfirmation,
 	}
 	if err := db.CreateUser(u); err != nil {
 		switch {
@@ -368,11 +368,11 @@ func SignUpPost(c *context.Context, cpt *captcha.Captcha, f form.Register) {
 	}
 
 	// Send confirmation email, no need for social account.
-	if conf.Service.RegisterEmailConfirm && u.ID > 1 {
+	if conf.Auth.RegisterEmailConfirm && u.ID > 1 {
 		email.SendActivateAccountMail(c.Context, db.NewMailerUser(u))
 		c.Data["IsSendRegisterMail"] = true
 		c.Data["Email"] = u.Email
-		c.Data["Hours"] = conf.Service.ActiveCodeLives / 60
+		c.Data["Hours"] = conf.Auth.ActivateCodeLives / 60
 		c.Success(ACTIVATE)
 
 		if err := c.Cache.Put(u.MailResendCacheKey(), 1, 180); err != nil {
@@ -393,11 +393,11 @@ func Activate(c *context.Context) {
 			return
 		}
 		// Resend confirmation email.
-		if conf.Service.RegisterEmailConfirm {
+		if conf.Auth.RequireEmailConfirmation {
 			if c.Cache.IsExist(c.User.MailResendCacheKey()) {
 				c.Data["ResendLimited"] = true
 			} else {
-				c.Data["Hours"] = conf.Service.ActiveCodeLives / 60
+				c.Data["Hours"] = conf.Auth.ActivateCodeLives / 60
 				email.SendActivateAccountMail(c.Context, db.NewMailerUser(c.User))
 
 				if err := c.Cache.Put(c.User.MailResendCacheKey(), 1, 180); err != nil {
@@ -482,7 +482,7 @@ func ForgotPasswdPost(c *context.Context) {
 	u, err := db.GetUserByEmail(emailAddr)
 	if err != nil {
 		if errors.IsUserNotExist(err) {
-			c.Data["Hours"] = conf.Service.ActiveCodeLives / 60
+			c.Data["Hours"] = conf.Auth.ActivateCodeLives / 60
 			c.Data["IsResetSent"] = true
 			c.Success(FORGOT_PASSWORD)
 			return
@@ -509,7 +509,7 @@ func ForgotPasswdPost(c *context.Context) {
 		log.Error("Failed to put cache key 'mail resend': %v", err)
 	}
 
-	c.Data["Hours"] = conf.Service.ActiveCodeLives / 60
+	c.Data["Hours"] = conf.Auth.ActivateCodeLives / 60
 	c.Data["IsResetSent"] = true
 	c.Success(FORGOT_PASSWORD)
 }

+ 3 - 3
internal/route/user/setting.go

@@ -262,7 +262,7 @@ func SettingsEmailPost(c *context.Context, f form.AddEmail) {
 	emailAddr := &db.EmailAddress{
 		UID:         c.User.ID,
 		Email:       f.Email,
-		IsActivated: !conf.Service.RegisterEmailConfirm,
+		IsActivated: !conf.Auth.RequireEmailConfirmation,
 	}
 	if err := db.AddEmailAddress(emailAddr); err != nil {
 		if db.IsErrEmailAlreadyUsed(err) {
@@ -274,13 +274,13 @@ func SettingsEmailPost(c *context.Context, f form.AddEmail) {
 	}
 
 	// Send confirmation email
-	if conf.Service.RegisterEmailConfirm {
+	if conf.Auth.RequireEmailConfirmation {
 		email.SendActivateEmailMail(c.Context, db.NewMailerUser(c.User), emailAddr.Email)
 
 		if err := c.Cache.Put("MailResendLimit_"+c.User.LowerName, c.User.LowerName, 180); err != nil {
 			log.Error("Set cache 'MailResendLimit' failed: %v", err)
 		}
-		c.Flash.Info(c.Tr("settings.add_email_confirmation_sent", emailAddr.Email, conf.Service.ActiveCodeLives/60))
+		c.Flash.Info(c.Tr("settings.add_email_confirmation_sent", emailAddr.Email, conf.Auth.ActivateCodeLives/60))
 	} else {
 		c.Flash.Success(c.Tr("settings.add_email_success"))
 	}

+ 42 - 29
templates/admin/config.tmpl

@@ -194,8 +194,6 @@
 						<dd>{{.Security.CookieUsername}}</dd>
 						<dt>{{.i18n.Tr "admin.config.security.cookie_secure"}}</dt>
 						<dd><i class="fa fa{{if .Security.CookieSecure}}-check{{end}}-square-o"></i></dd>
-						<dt>{{.i18n.Tr "admin.config.security.reverse_proxy_auth_user"}}</dt>
-						<dd>{{.Security.ReverseProxyAuthenticationUser}}</dd>
 						<dt>{{.i18n.Tr "admin.config.security.enable_login_status_cookie"}}</dt>
 						<dd><i class="fa fa{{if .Security.EnableLoginStatusCookie}}-check{{end}}-square-o"></i></dd>
 						<dt>{{.i18n.Tr "admin.config.security.login_status_cookie_name"}}</dt>
@@ -261,6 +259,48 @@
 					</dl>
 				</div>
 
+				{{/* Authentication settings */}}
+				<h4 class="ui top attached header">
+					{{.i18n.Tr "admin.config.auth_config"}}
+				</h4>
+				<div class="ui attached table segment">
+					<dl class="dl-horizontal admin-dl-horizontal">
+						<dt>{{.i18n.Tr "admin.config.auth.activate_code_lives"}}</dt>
+						<dd>{{.Auth.ActivateCodeLives}} {{.i18n.Tr "tool.raw_minutes"}}</dd>
+						<dt>{{.i18n.Tr "admin.config.auth.reset_password_code_lives"}}</dt>
+						<dd>{{.Auth.ResetPasswordCodeLives}} {{.i18n.Tr "tool.raw_minutes"}}</dd>
+						<dt>{{.i18n.Tr "admin.config.auth.require_email_confirm"}}</dt>
+						<dd><i class="fa fa{{if .Auth.RequireEmailConfirmation}}-check{{end}}-square-o"></i></dd>
+						<dt>{{.i18n.Tr "admin.config.auth.require_sign_in_view"}}</dt>
+						<dd><i class="fa fa{{if .Auth.RequireSigninView}}-check{{end}}-square-o"></i></dd>
+						<dt>{{.i18n.Tr "admin.config.auth.disable_registration"}}</dt>
+						<dd><i class="fa fa{{if .Auth.DisableRegistration}}-check{{end}}-square-o"></i></dd>
+						<dt>{{.i18n.Tr "admin.config.auth.enable_registration_captcha"}}</dt>
+						<dd><i class="fa fa{{if .Auth.EnableRegistrationCaptcha}}-check{{end}}-square-o"></i></dd>
+
+						<div class="ui divider"></div>
+
+						<dt>{{.i18n.Tr "admin.config.auth.enable_reverse_proxy_authentication"}}</dt>
+						<dd><i class="fa fa{{if .Auth.EnableReverseProxyAuthentication}}-check{{end}}-square-o"></i></dd>
+						<dt>{{.i18n.Tr "admin.config.auth.enable_reverse_proxy_auto_registration"}}</dt>
+						<dd><i class="fa fa{{if .Auth.EnableReverseProxyAutoRegistration}}-check{{end}}-square-o"></i></dd>
+						<dt>{{.i18n.Tr "admin.config.auth.reverse_proxy_authentication_header"}}</dt>
+						<dd><code>{{.Auth.ReverseProxyAuthenticationHeader}}</code></dd>
+					</dl>
+				</div>
+
+
+				{{/* User settings */}}
+				<h4 class="ui top attached header">
+					{{.i18n.Tr "admin.config.user_config"}}
+				</h4>
+				<div class="ui attached table segment">
+					<dl class="dl-horizontal admin-dl-horizontal">
+						<dt>{{.i18n.Tr "admin.config.user.enable_email_notify"}}</dt>
+						<dd><i class="fa fa{{if .User.EnableEmailNotification}}-check{{end}}-square-o"></i></dd>
+					</dl>
+				</div>
+
 				<!-- HTTP Configuration -->
 				<h4 class="ui top attached header">
 					{{.i18n.Tr "admin.config.http_config"}}
@@ -278,33 +318,6 @@
 					</dl>
 				</div>
 
-				<h4 class="ui top attached header">
-					{{.i18n.Tr "admin.config.service_config"}}
-				</h4>
-				<div class="ui attached table segment">
-					<dl class="dl-horizontal admin-dl-horizontal">
-						<dt>{{.i18n.Tr "admin.config.register_email_confirm"}}</dt>
-						<dd><i class="fa fa{{if .Service.RegisterEmailConfirm}}-check{{end}}-square-o"></i></dd>
-						<dt>{{.i18n.Tr "admin.config.disable_register"}}</dt>
-						<dd><i class="fa fa{{if .Service.DisableRegistration}}-check{{end}}-square-o"></i></dd>
-						<dt>{{.i18n.Tr "admin.config.show_registration_button"}}</dt>
-						<dd><i class="fa fa{{if .Service.ShowRegistrationButton}}-check{{end}}-square-o"></i></dd>
-						<dt>{{.i18n.Tr "admin.config.require_sign_in_view"}}</dt>
-						<dd><i class="fa fa{{if .Service.RequireSignInView}}-check{{end}}-square-o"></i></dd>
-						<dt>{{.i18n.Tr "admin.config.mail_notify"}}</dt>
-						<dd><i class="fa fa{{if .Service.EnableNotifyMail}}-check{{end}}-square-o"></i></dd>
-						{{/*<dt>{{.i18n.Tr "admin.config.disable_key_size_check"}}</dt>
-						<dd><i class="fa fa{{if .Service.DisableMinimumKeySizeCheck}}-check{{end}}-square-o"></i></dd>*/}}
-						<dt>{{.i18n.Tr "admin.config.enable_captcha"}}</dt>
-						<dd><i class="fa fa{{if .Service.EnableCaptcha}}-check{{end}}-square-o"></i></dd>
-						<div class="ui divider"></div>
-						<dt>{{.i18n.Tr "admin.config.active_code_lives"}}</dt>
-						<dd>{{.Service.ActiveCodeLives}} {{.i18n.Tr "tool.raw_minutes"}}</dd>
-						<dt>{{.i18n.Tr "admin.config.reset_password_code_lives"}}</dt>
-						<dd>{{.Service.ResetPwdCodeLives}} {{.i18n.Tr "tool.raw_minutes"}}</dd>
-					</dl>
-				</div>
-
 				<h4 class="ui top attached header">
 					{{.i18n.Tr "admin.config.webhook_config"}}
 				</h4>

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů