conf: overhaul auth and user settings (#5942)

* conf: overhaul auth and user settings

* ci: update travis Go versions
pull/5943/head
ᴜɴᴋɴᴡᴏɴ 2020-02-27 18:06:38 +08:00 committed by GitHub
parent cf3d55fa10
commit 7950f2d17d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 242 additions and 200 deletions

View File

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

View File

@ -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 `[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] 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 `[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 `[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 ### Fixed

View File

@ -160,8 +160,6 @@ COOKIE_REMEMBER_NAME = gogs_incredible
COOKIE_USERNAME = gogs_awesome COOKIE_USERNAME = gogs_awesome
; Whether to set secure cookie. ; Whether to set secure cookie.
COOKIE_SECURE = false 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. ; Whether to set cookie to indicate user login status.
ENABLE_LOGIN_STATUS_COOKIE = false ENABLE_LOGIN_STATUS_COOKIE = false
; The cookie name to store user login status. ; 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. ; It is used to support older mail clients and make spam filters happier.
ADD_PLAIN_TEXT_ALT = false 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 ; Attachment settings for releases
[release.attachment] [release.attachment]
; Whether attachments are enabled. Defaults to `true` ; 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 (non-admin) users to create organizations
DISABLE_REGULAR_ORG_CREATION = false 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] [webhook]
; Types are enabled for users to use, can be "gogs", "slack", "discord", "dingtalk" ; Types are enabled for users to use, can be "gogs", "slack", "discord", "dingtalk"
TYPES = gogs, slack, discord, dingtalk TYPES = gogs, slack, discord, dingtalk

View File

@ -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_failed = Failed to send test email to '%s': %v
config.email.test_mail_sent = Test email has been sent to '%s'. 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.log_file_root_path = Log File Root Path
config.http_config = HTTP Configuration config.http_config = HTTP Configuration
config.http_access_control_allow_origin = Access Control Allow Origin 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.webhook_config = Webhook Configuration
config.queue_length = Queue Length config.queue_length = Queue Length

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

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

View File

@ -23,8 +23,8 @@ import (
"gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/conf"
"gogs.io/gogs/internal/db" "gogs.io/gogs/internal/db"
"gogs.io/gogs/internal/db/errors" "gogs.io/gogs/internal/db/errors"
"gogs.io/gogs/internal/httplib"
"gogs.io/gogs/internal/email" "gogs.io/gogs/internal/email"
"gogs.io/gogs/internal/httplib"
"gogs.io/gogs/internal/template" "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, // Post-receive hook does more than just gather Git information,
// so we need to setup additional services for email notifications. // so we need to setup additional services for email notifications.
conf.NewPostReceiveHookServices()
email.NewContext() email.NewContext()
isWiki := strings.Contains(os.Getenv(db.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/") isWiki := strings.Contains(os.Getenv(db.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/")

View File

@ -220,12 +220,11 @@ func runServ(c *cli.Context) error {
} }
} }
} else { } 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). // 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 // 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 case, a server // we should give read access only in repositories where this deploy key is in use. In other cases,
// or system using an active deploy key can get read access to all the repositories in a Gogs service. // a server or system using an active deploy key can get read access to all repositories on a Gogs instace.
if key.IsDeployKey() && conf.Service.RequireSignInView { if key.IsDeployKey() && conf.Auth.RequireSigninView {
checkDeployKey(key, repo) checkDeployKey(key, repo)
} }
} }

View File

@ -171,7 +171,7 @@ func runWeb(c *cli.Context) error {
m := newMacaron() m := newMacaron()
reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true}) 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}) ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true})
reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true}) reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true})

View File

@ -61,6 +61,8 @@ var File *ini.File
// It is safe to call this function multiple times with desired `customConf`, but it is // It is safe to call this function multiple times with desired `customConf`, but it is
// not concurrent safe. // 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. // ⚠️ WARNING: Do not print anything in this function other than wanrings.
func Init(customConf string) error { func Init(customConf string) error {
var err error var err error
@ -232,6 +234,26 @@ func Init(customConf string) error {
Email.FromEmail = parsed.Address 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() handleDeprecated()
// TODO // 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() { func newCacheService() {
CacheAdapter = File.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"}) CacheAdapter = File.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"})
switch CacheAdapter { switch CacheAdapter {
@ -713,53 +710,11 @@ func newSessionService() {
log.Trace("Session service is enabled") 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() { func NewServices() {
newService()
newCacheService() newCacheService()
newSessionService() newSessionService()
newRegisterMailService()
newNotifyMailService()
} }
// HookMode indicates whether program starts as Git server-side hook callback. // 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 var HookMode bool
// NewPostReceiveHookServices initializes all services that are needed by
// Git server-side post-receive hook callback.
func NewPostReceiveHookServices() {
HookMode = true
newService()
newNotifyMailService()
}

View File

@ -148,9 +148,11 @@ var (
CookieRememberName string CookieRememberName string
CookieUsername string CookieUsername string
CookieSecure bool CookieSecure bool
ReverseProxyAuthenticationUser string
EnableLoginStatusCookie bool EnableLoginStatusCookie bool
LoginStatusCookieName string LoginStatusCookieName string
// Deprecated: Use Auth.ReverseProxyAuthenticationHeader instead, will be removed in 0.13.
ReverseProxyAuthenticationUser string
} }
// Email settings // Email settings
@ -179,6 +181,36 @@ var (
// Deprecated: Use Password instead, will be removed in 0.13. // Deprecated: Use Password instead, will be removed in 0.13.
Passwd string 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. // handleDeprecated transfers deprecated values to the new ones when set.
@ -210,4 +242,30 @@ func handleDeprecated() {
Email.Password = Email.Passwd Email.Password = Email.Passwd
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
}
} }

View File

@ -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.SetCookie("redirect_to", url.QueryEscape(conf.Server.Subpath+c.Req.RequestURI), 0, conf.Server.Subpath)
c.Redirect(conf.Server.Subpath + "/user/login") c.Redirect(conf.Server.Subpath + "/user/login")
return 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.Data["Title"] = c.Tr("auth.active_your_account")
c.HTML(200, "user/auth/activate") c.HTML(200, "user/auth/activate")
return return

View File

@ -323,7 +323,7 @@ func Contexter() macaron.Handler {
log.Trace("Session ID: %s", sess.ID()) log.Trace("Session ID: %s", sess.ID())
log.Trace("CSRF Token: %v", c.Data["CSRFToken"]) 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.Data["ShowFooterBranding"] = conf.ShowFooterBranding
c.renderNoticeBanner() c.renderNoticeBanner()

View File

@ -10,9 +10,9 @@ import (
"github.com/unknwon/com" "github.com/unknwon/com"
log "unknwon.dev/clog/v2" log "unknwon.dev/clog/v2"
"gogs.io/gogs/internal/conf"
"gogs.io/gogs/internal/email" "gogs.io/gogs/internal/email"
"gogs.io/gogs/internal/markup" "gogs.io/gogs/internal/markup"
"gogs.io/gogs/internal/conf"
) )
func (issue *Issue) MailSubject() string { 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. // 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. // 2. Users who are not in 1. but get mentioned in current issue/comment.
func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string) error { func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string) error {
if !conf.Service.EnableNotifyMail { if !conf.User.EnableEmailNotification {
return nil return nil
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,7 +22,7 @@ const (
func Home(c *context.Context) { func Home(c *context.Context) {
if c.IsLogged { 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.Data["Title"] = c.Tr("auth.active_your_account")
c.Success(user2.ACTIVATE) c.Success(user2.ACTIVATE)
} else { } else {

View File

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

View File

@ -77,7 +77,7 @@ func HTTPContexter() macaron.Handler {
} }
// Authentication is not required for pulling from public repositories. // 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{ c.Map(&HTTPContext{
Context: c, Context: c,
}) })

View File

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

View File

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

View File

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

View File

@ -194,8 +194,6 @@
<dd>{{.Security.CookieUsername}}</dd> <dd>{{.Security.CookieUsername}}</dd>
<dt>{{.i18n.Tr "admin.config.security.cookie_secure"}}</dt> <dt>{{.i18n.Tr "admin.config.security.cookie_secure"}}</dt>
<dd><i class="fa fa{{if .Security.CookieSecure}}-check{{end}}-square-o"></i></dd> <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> <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> <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> <dt>{{.i18n.Tr "admin.config.security.login_status_cookie_name"}}</dt>
@ -261,6 +259,48 @@
</dl> </dl>
</div> </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 --> <!-- HTTP Configuration -->
<h4 class="ui top attached header"> <h4 class="ui top attached header">
{{.i18n.Tr "admin.config.http_config"}} {{.i18n.Tr "admin.config.http_config"}}
@ -278,33 +318,6 @@
</dl> </dl>
</div> </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"> <h4 class="ui top attached header">
{{.i18n.Tr "admin.config.webhook_config"}} {{.i18n.Tr "admin.config.webhook_config"}}
</h4> </h4>