Resolve #29660 Follow #29522 and #29609 Add a warning for disallowed email domains when admins manually add/edit users. Thanks @yp05327 for the [comment](https://github.com/go-gitea/gitea/pull/29605#issuecomment-1980105119) ![image](https://github.com/go-gitea/gitea/assets/15528715/6737b221-a3a2-4180-9ef8-b846c10f96e0)tags/v1.22.0-rc0
// validateEmailDomain checks whether the email domain is allowed or blocked | // validateEmailDomain checks whether the email domain is allowed or blocked | ||||
func validateEmailDomain(email string) error { | func validateEmailDomain(email string) error { | ||||
// if there is no allow list, then check email against block list | |||||
if len(setting.Service.EmailDomainAllowList) == 0 && | |||||
validation.IsEmailDomainListed(setting.Service.EmailDomainBlockList, email) { | |||||
if !IsEmailDomainAllowed(email) { | |||||
return ErrEmailInvalid{email} | return ErrEmailInvalid{email} | ||||
} | } | ||||
// if there is an allow list, then check email against allow list | |||||
if len(setting.Service.EmailDomainAllowList) > 0 && | |||||
!validation.IsEmailDomainListed(setting.Service.EmailDomainAllowList, email) { | |||||
return ErrEmailInvalid{email} | |||||
return nil | |||||
} | |||||
func IsEmailDomainAllowed(email string) bool { | |||||
if len(setting.Service.EmailDomainAllowList) == 0 { | |||||
return !validation.IsEmailDomainListed(setting.Service.EmailDomainBlockList, email) | |||||
} | } | ||||
return nil | |||||
return validation.IsEmailDomainListed(setting.Service.EmailDomainAllowList, email) | |||||
} | } |
team_no_units_error = Allow access to at least one repository section. | team_no_units_error = Allow access to at least one repository section. | ||||
email_been_used = The email address is already used. | email_been_used = The email address is already used. | ||||
email_invalid = The email address is invalid. | email_invalid = The email address is invalid. | ||||
email_domain_is_not_allowed = The domain of user email <b>%s</b> conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST. Please ensure your operation is expected. | |||||
openid_been_used = The OpenID address "%s" is already used. | openid_been_used = The OpenID address "%s" is already used. | ||||
username_password_incorrect = Username or password is incorrect. | username_password_incorrect = Username or password is incorrect. | ||||
password_complexity = Password does not pass complexity requirements: | password_complexity = Password does not pass complexity requirements: |
} | } | ||||
return | return | ||||
} | } | ||||
if !user_model.IsEmailDomainAllowed(u.Email) { | |||||
ctx.Resp.Header().Add("X-Gitea-Warning", fmt.Sprintf("the domain of user email %s conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", u.Email)) | |||||
} | |||||
log.Trace("Account created by admin (%s): %s", ctx.Doer.Name, u.Name) | log.Trace("Account created by admin (%s): %s", ctx.Doer.Name, u.Name) | ||||
// Send email notification. | // Send email notification. | ||||
} | } | ||||
return | return | ||||
} | } | ||||
if !user_model.IsEmailDomainAllowed(*form.Email) { | |||||
ctx.Resp.Header().Add("X-Gitea-Warning", fmt.Sprintf("the domain of user email %s conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", *form.Email)) | |||||
} | |||||
} | } | ||||
opts := &user_service.UpdateOptions{ | opts := &user_service.UpdateOptions{ |
} | } | ||||
return | return | ||||
} | } | ||||
if !user_model.IsEmailDomainAllowed(u.Email) { | |||||
ctx.Flash.Warning(ctx.Tr("form.email_domain_is_not_allowed", u.Email)) | |||||
} | |||||
log.Trace("Account created by admin (%s): %s", ctx.Doer.Name, u.Name) | log.Trace("Account created by admin (%s): %s", ctx.Doer.Name, u.Name) | ||||
// Send email notification. | // Send email notification. | ||||
} | } | ||||
return | return | ||||
} | } | ||||
if !user_model.IsEmailDomainAllowed(form.Email) { | |||||
ctx.Flash.Warning(ctx.Tr("form.email_domain_is_not_allowed", form.Email)) | |||||
} | |||||
} | } | ||||
opts := &user_service.UpdateOptions{ | opts := &user_service.UpdateOptions{ |
"strings" | "strings" | ||||
auth_model "code.gitea.io/gitea/models/auth" | auth_model "code.gitea.io/gitea/models/auth" | ||||
user_model "code.gitea.io/gitea/models/user" | |||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"code.gitea.io/gitea/modules/structs" | "code.gitea.io/gitea/modules/structs" | ||||
"code.gitea.io/gitea/modules/validation" | |||||
"code.gitea.io/gitea/modules/web/middleware" | "code.gitea.io/gitea/modules/web/middleware" | ||||
"code.gitea.io/gitea/services/context" | "code.gitea.io/gitea/services/context" | ||||
// domains in the whitelist or if it doesn't match any of | // domains in the whitelist or if it doesn't match any of | ||||
// domains in the blocklist, if any such list is not empty. | // domains in the blocklist, if any such list is not empty. | ||||
func (f *RegisterForm) IsEmailDomainAllowed() bool { | func (f *RegisterForm) IsEmailDomainAllowed() bool { | ||||
if len(setting.Service.EmailDomainAllowList) == 0 { | |||||
return !validation.IsEmailDomainListed(setting.Service.EmailDomainBlockList, f.Email) | |||||
} | |||||
return validation.IsEmailDomainListed(setting.Service.EmailDomainAllowList, f.Email) | |||||
return user_model.IsEmailDomainAllowed(f.Email) | |||||
} | } | ||||
// MustChangePasswordForm form for updating your password after account creation | // MustChangePasswordForm form for updating your password after account creation |
"password": "allowedUser1_pass", | "password": "allowedUser1_pass", | ||||
"must_change_password": "true", | "must_change_password": "true", | ||||
}).AddTokenAuth(token) | }).AddTokenAuth(token) | ||||
MakeRequest(t, req, http.StatusCreated) | |||||
resp := MakeRequest(t, req, http.StatusCreated) | |||||
assert.Equal(t, "the domain of user email allowedUser1@example1.org conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", resp.Header().Get("X-Gitea-Warning")) | |||||
req = NewRequest(t, "DELETE", "/api/v1/admin/users/allowedUser1").AddTokenAuth(token) | req = NewRequest(t, "DELETE", "/api/v1/admin/users/allowedUser1").AddTokenAuth(token) | ||||
MakeRequest(t, req, http.StatusNoContent) | MakeRequest(t, req, http.StatusNoContent) | ||||
SourceID: 0, | SourceID: 0, | ||||
Email: &newEmail, | Email: &newEmail, | ||||
}).AddTokenAuth(token) | }).AddTokenAuth(token) | ||||
MakeRequest(t, req, http.StatusOK) | |||||
resp := MakeRequest(t, req, http.StatusOK) | |||||
assert.Equal(t, "the domain of user email user2@example1.com conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST", resp.Header().Get("X-Gitea-Warning")) | |||||
originalEmail := "user2@example.com" | originalEmail := "user2@example.com" | ||||
req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ | req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ |