From e672015264722841c0e8a24590546dad2b59c0bf Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Tue, 23 Oct 2018 23:56:12 +0100 Subject: [PATCH 1/6] implement email domain whitelist --- custom/conf/app.ini.sample | 3 + .../doc/advanced/config-cheat-sheet.en-us.md | 2 + modules/auth/user_form.go | 28 +++++++++ modules/auth/user_form_test.go | 63 +++++++++++++++++++ modules/setting/setting.go | 3 +- options/locale/locale_en-US.ini | 1 + routers/user/auth.go | 6 +- 7 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 modules/auth/user_form_test.go diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 47d7bcb6a405..809d00bb0a95 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -306,6 +306,9 @@ ACTIVE_CODE_LIVE_MINUTES = 180 RESET_PASSWD_CODE_LIVE_MINUTES = 180 ; Whether a new user needs to confirm their email when registering. REGISTER_EMAIL_CONFIRM = false +; List of domain names that are allowed to be used to register on a Gitea instance +; gitea.io example.com +EMAIL_DOMAIN_WHITELIST= ; Disallow registration, only allow admins to create accounts. DISABLE_REGISTRATION = false ; Allow registration only using third part services, it works only when DISABLE_REGISTRATION is false diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 4dbc4c0d7cdf..262892cbb4b7 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -194,6 +194,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha. - `DEFAULT_ENABLE_DEPENDENCIES`: **true** Enable this to have dependencies enabled by default. - `ENABLE_USER_HEATMAP`: **true** Enable this to display the heatmap on users profiles. +- `EMAIL_DOMAIN_WHITELIST`: **\**: If non-empty, list of domain names that can only be used to register + on this instance. ## Webhook (`webhook`) diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 43ddb29c76e6..4714c53a0340 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -6,6 +6,9 @@ package auth import ( "mime/multipart" + "strings" + + "code.gitea.io/gitea/modules/setting" "github.com/go-macaron/binding" "gopkg.in/macaron.v1" @@ -84,6 +87,31 @@ func (f *RegisterForm) Validate(ctx *macaron.Context, errs binding.Errors) bindi return validate(errs, ctx.Data, f, ctx.Locale) } +// IsEmailDomainWhitelisted validates that the email address +// provided by the user matches what has been configured . +// If the domain whitelist from the config is empty, it marks the +// email as whitelisted +func (f RegisterForm) IsEmailDomainWhitelisted() bool { + if len(setting.Service.EmailDomainWhitelist) == 0 { + return true + } + + n := strings.LastIndex(f.Email, "@") + if n <= 0 { + return false + } + + domain := f.Email[n+1:] + + for _, v := range setting.Service.EmailDomainWhitelist { + if v == domain { + return true + } + } + + return false +} + // MustChangePasswordForm form for updating your password after account creation // by an admin type MustChangePasswordForm struct { diff --git a/modules/auth/user_form_test.go b/modules/auth/user_form_test.go new file mode 100644 index 000000000000..9df2b18707b5 --- /dev/null +++ b/modules/auth/user_form_test.go @@ -0,0 +1,63 @@ +// Copyright 2018 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package auth + +import ( + "testing" + + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" +) + +func TestRegisterForm_IsDomainWhiteList_Empty(t *testing.T) { + _ = setting.Service + + setting.Service.EmailDomainWhitelist = []string{} + + form := RegisterForm{} + + assert.True(t, form.IsEmailDomainWhitelisted()) +} + +func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) { + _ = setting.Service + + setting.Service.EmailDomainWhitelist = []string{"gitea.io"} + + tt := []struct { + email string + }{ + {"securitygieqqq"}, + {"hdudhdd"}, + } + + for _, v := range tt { + form := RegisterForm{Email: v.email} + + assert.False(t, form.IsEmailDomainWhitelisted()) + } +} + +func TestRegisterForm_IsDomainWhiteList_ValidEmail(t *testing.T) { + _ = setting.Service + + setting.Service.EmailDomainWhitelist = []string{"gitea.io"} + + tt := []struct { + email string + valid bool + }{ + {"security@gitea.io", true}, + {"hdudhdd", false}, + {"seee@example.com", false}, + } + + for _, v := range tt { + form := RegisterForm{Email: v.email} + + assert.Equal(t, v.valid, form.IsEmailDomainWhitelisted()) + } +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 0523c3089814..26dd49c4b0ba 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -26,7 +26,6 @@ import ( "code.gitea.io/gitea/modules/log" _ "code.gitea.io/gitea/modules/minwinsvc" // import minwinsvc for windows services "code.gitea.io/gitea/modules/user" - "github.com/Unknwon/com" _ "github.com/go-macaron/cache/memcache" // memcache plugin for cache _ "github.com/go-macaron/cache/redis" @@ -1200,6 +1199,7 @@ var Service struct { ActiveCodeLives int ResetPwdCodeLives int RegisterEmailConfirm bool + EmailDomainWhitelist []string DisableRegistration bool AllowOnlyExternalRegistration bool ShowRegistrationButton bool @@ -1233,6 +1233,7 @@ func newService() { Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180) Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool() Service.AllowOnlyExternalRegistration = sec.Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").MustBool() + Service.EmailDomainWhitelist = sec.Key("EMAIL_DOMAIN_WHITELIST").Strings(" ") Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration)) Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool() Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool() diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 6855e0376b37..cc2a97e11593 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -237,6 +237,7 @@ openid_register_title = Create new account openid_register_desc = The chosen OpenID URI is unknown. Associate it with a new account here. openid_signin_desc = Enter your OpenID URI. For example: https://anne.me, bob.openid.org.cn or gnusocial.net/carry. disable_forgot_password_mail = Password reset is disabled. Please contact your site administrator. +email_domain_blacklisted = You cannot register with your email address. [mail] activate_account = Please activate your account diff --git a/routers/user/auth.go b/routers/user/auth.go index a4a0ee3e6a0f..deaeccdb909d 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -21,7 +21,6 @@ import ( "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - "github.com/go-macaron/captcha" "github.com/markbates/goth" "github.com/tstranex/u2f" @@ -926,6 +925,11 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo } } + if !form.IsEmailDomainWhitelisted() { + ctx.RenderWithErr(ctx.Tr("auth.email_domain_blacklisted"), tplSignUp, &form) + return + } + if form.Password != form.Retype { ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplSignUp, &form) From 4fdd1aea44222a3b74de2f69bd5c96a1e783dd47 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Thu, 25 Oct 2018 14:05:08 +0100 Subject: [PATCH 2/6] change delimiter to to keep in sync with other sections of the code --- custom/conf/app.ini.sample | 2 +- modules/setting/setting.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index 809d00bb0a95..af826ea02e0d 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -307,7 +307,7 @@ RESET_PASSWD_CODE_LIVE_MINUTES = 180 ; Whether a new user needs to confirm their email when registering. REGISTER_EMAIL_CONFIRM = false ; List of domain names that are allowed to be used to register on a Gitea instance -; gitea.io example.com +; gitea.io,example.com EMAIL_DOMAIN_WHITELIST= ; Disallow registration, only allow admins to create accounts. DISABLE_REGISTRATION = false diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 26dd49c4b0ba..701380c2f240 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1233,7 +1233,7 @@ func newService() { Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180) Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool() Service.AllowOnlyExternalRegistration = sec.Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").MustBool() - Service.EmailDomainWhitelist = sec.Key("EMAIL_DOMAIN_WHITELIST").Strings(" ") + Service.EmailDomainWhitelist = sec.Key("EMAIL_DOMAIN_WHITELIST").Strings(",") Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration)) Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool() Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool() From 7115126bc1965267745facd3b3847849d972cb17 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Thu, 25 Oct 2018 14:12:08 +0100 Subject: [PATCH 3/6] update method name --- modules/auth/user_form.go | 4 ++-- modules/auth/user_form_test.go | 6 +++--- routers/user/auth.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 4714c53a0340..54e631339246 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -87,11 +87,11 @@ func (f *RegisterForm) Validate(ctx *macaron.Context, errs binding.Errors) bindi return validate(errs, ctx.Data, f, ctx.Locale) } -// IsEmailDomainWhitelisted validates that the email address +// IsEmaildomainwhitelisted validates that the email address // provided by the user matches what has been configured . // If the domain whitelist from the config is empty, it marks the // email as whitelisted -func (f RegisterForm) IsEmailDomainWhitelisted() bool { +func (f RegisterForm) IsEmaildomainwhitelisted() bool { if len(setting.Service.EmailDomainWhitelist) == 0 { return true } diff --git a/modules/auth/user_form_test.go b/modules/auth/user_form_test.go index 9df2b18707b5..645596dd1d82 100644 --- a/modules/auth/user_form_test.go +++ b/modules/auth/user_form_test.go @@ -19,7 +19,7 @@ func TestRegisterForm_IsDomainWhiteList_Empty(t *testing.T) { form := RegisterForm{} - assert.True(t, form.IsEmailDomainWhitelisted()) + assert.True(t, form.IsEmaildomainwhitelisted()) } func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) { @@ -37,7 +37,7 @@ func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) { for _, v := range tt { form := RegisterForm{Email: v.email} - assert.False(t, form.IsEmailDomainWhitelisted()) + assert.False(t, form.IsEmaildomainwhitelisted()) } } @@ -58,6 +58,6 @@ func TestRegisterForm_IsDomainWhiteList_ValidEmail(t *testing.T) { for _, v := range tt { form := RegisterForm{Email: v.email} - assert.Equal(t, v.valid, form.IsEmailDomainWhitelisted()) + assert.Equal(t, v.valid, form.IsEmaildomainwhitelisted()) } } diff --git a/routers/user/auth.go b/routers/user/auth.go index deaeccdb909d..dae076adcd9c 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -925,7 +925,7 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo } } - if !form.IsEmailDomainWhitelisted() { + if !form.IsEmaildomainwhitelisted() { ctx.RenderWithErr(ctx.Tr("auth.email_domain_blacklisted"), tplSignUp, &form) return } From 2f475d1bf25f3df62fd3c03c704f2993ab251416 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Fri, 2 Nov 2018 01:48:33 +0100 Subject: [PATCH 4/6] add newline --- modules/setting/setting.go | 1 + routers/user/auth.go | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 2d3e6e3289a4..b612e590772a 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/log" _ "code.gitea.io/gitea/modules/minwinsvc" // import minwinsvc for windows services "code.gitea.io/gitea/modules/user" + "github.com/Unknwon/com" _ "github.com/go-macaron/cache/memcache" // memcache plugin for cache _ "github.com/go-macaron/cache/redis" diff --git a/routers/user/auth.go b/routers/user/auth.go index 9cb456231810..55eaa43d1aeb 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + "github.com/go-macaron/captcha" "github.com/markbates/goth" "github.com/tstranex/u2f" From 512c2f2ded30161b79b538c97b944ec0f91b2ea5 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Fri, 2 Nov 2018 09:05:38 +0100 Subject: [PATCH 5/6] update function naming and use strings#ToLower --- modules/auth/user_form.go | 8 ++++---- modules/auth/user_form_test.go | 7 ++++--- routers/user/auth.go | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 54e631339246..4209ad2a6742 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -87,11 +87,11 @@ func (f *RegisterForm) Validate(ctx *macaron.Context, errs binding.Errors) bindi return validate(errs, ctx.Data, f, ctx.Locale) } -// IsEmaildomainwhitelisted validates that the email address +// IsEmailDomainWhitelisted validates that the email address // provided by the user matches what has been configured . // If the domain whitelist from the config is empty, it marks the // email as whitelisted -func (f RegisterForm) IsEmaildomainwhitelisted() bool { +func (f RegisterForm) IsEmailDomainWhitelisted() bool { if len(setting.Service.EmailDomainWhitelist) == 0 { return true } @@ -101,10 +101,10 @@ func (f RegisterForm) IsEmaildomainwhitelisted() bool { return false } - domain := f.Email[n+1:] + domain := strings.ToLower(f.Email[n+1:]) for _, v := range setting.Service.EmailDomainWhitelist { - if v == domain { + if strings.ToLower(v) == domain { return true } } diff --git a/modules/auth/user_form_test.go b/modules/auth/user_form_test.go index 645596dd1d82..084174622e15 100644 --- a/modules/auth/user_form_test.go +++ b/modules/auth/user_form_test.go @@ -19,7 +19,7 @@ func TestRegisterForm_IsDomainWhiteList_Empty(t *testing.T) { form := RegisterForm{} - assert.True(t, form.IsEmaildomainwhitelisted()) + assert.True(t, form.IsEmailDomainWhitelisted()) } func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) { @@ -37,7 +37,7 @@ func TestRegisterForm_IsDomainWhiteList_InvalidEmail(t *testing.T) { for _, v := range tt { form := RegisterForm{Email: v.email} - assert.False(t, form.IsEmaildomainwhitelisted()) + assert.False(t, form.IsEmailDomainWhitelisted()) } } @@ -51,6 +51,7 @@ func TestRegisterForm_IsDomainWhiteList_ValidEmail(t *testing.T) { valid bool }{ {"security@gitea.io", true}, + {"security@gITea.io", true}, {"hdudhdd", false}, {"seee@example.com", false}, } @@ -58,6 +59,6 @@ func TestRegisterForm_IsDomainWhiteList_ValidEmail(t *testing.T) { for _, v := range tt { form := RegisterForm{Email: v.email} - assert.Equal(t, v.valid, form.IsEmaildomainwhitelisted()) + assert.Equal(t, v.valid, form.IsEmailDomainWhitelisted()) } } diff --git a/routers/user/auth.go b/routers/user/auth.go index 55eaa43d1aeb..24b35e6f6227 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -948,7 +948,7 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo } } - if !form.IsEmaildomainwhitelisted() { + if !form.IsEmailDomainWhitelisted() { ctx.RenderWithErr(ctx.Tr("auth.email_domain_blacklisted"), tplSignUp, &form) return } From 2f35804137e45ec0c94335e6de18ea1a8fa2724b Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Thu, 15 Nov 2018 01:48:10 +0100 Subject: [PATCH 6/6] Add Gitea authors copyright --- modules/auth/user_form.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 4209ad2a6742..c281672fe121 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -1,4 +1,5 @@ // Copyright 2014 The Gogs Authors. All rights reserved. +// Copyright 2018 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file.