Requires `Mailer` to be enabled.
- `DISABLE_REGISTRATION`: **false**: Disable registration, after which only admin can create
accounts for users.
+- `REQUIRE_EXTERNAL_REGISTRATION_PASSWORD`: **false**: Enable this to force externally created
+ accounts (via GitHub, OpenID Connect, etc) to create a password. Warning: enabling this will
+ decrease security, so you should only enable it if you know what you're doing.
- `REQUIRE_SIGNIN_VIEW`: **false**: Enable this to force users to log in to view any page.
- `ENABLE_NOTIFY_MAIL`: **false**: Enable this to send e-mail to watchers of a repository when
something happens, like creating issues. Requires `Mailer` to be enabled.
- `ENABLE_REVERSE_PROXY_EMAIL`: **false**: Enable this to allow to auto-registration with a
provided email rather than a generated email.
- `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration.
+- `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation
+ even for External Accounts (i.e. GitHub, OpenID Connect, etc). You must `ENABLE_CAPTCHA` also.
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha\]
- `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha.
- `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha.
## Metrics (`metrics`)
-- `ENABLED`: **false**: Enables /metrics endpoint for prometheus.
+- `ENABLED`: **false**: Enables /metrics endpoint for prometheus.
- `TOKEN`: **\<empty\>**: You need to specify the token, if you want to include in the authorization the metrics . The same token need to be used in prometheus parameters `bearer_token` or `bearer_token_file`.
## API (`api`)
// LinkAccount shows the page where the user can decide to login or create a new account
func LinkAccount(ctx *context.Context) {
+ ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationCaptcha || setting.Service.AllowOnlyExternalRegistration
ctx.Data["Title"] = ctx.Tr("link_account")
ctx.Data["LinkAccountMode"] = true
- ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
+ ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha
ctx.Data["CaptchaType"] = setting.Service.CaptchaType
ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
// LinkAccountPostSignIn handle the coupling of external account with another account using signIn
func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) {
+ ctx.Data["DisablePassword"] = setting.Service.AllowOnlyExternalRegistration
ctx.Data["Title"] = ctx.Tr("link_account")
ctx.Data["LinkAccountMode"] = true
ctx.Data["LinkAccountModeSignIn"] = true
- ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
+ ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha
ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
ctx.Data["CaptchaType"] = setting.Service.CaptchaType
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
// LinkAccountPostRegister handle the creation of a new account for an external account using signUp
func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterForm) {
+ // TODO Make insecure passwords optional for local accounts also,
+ // once email-based Second-Factor Auth is available
+ ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationCaptcha || setting.Service.AllowOnlyExternalRegistration
ctx.Data["Title"] = ctx.Tr("link_account")
ctx.Data["LinkAccountMode"] = true
ctx.Data["LinkAccountModeRegister"] = true
- ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
+ ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha
ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
ctx.Data["CaptchaType"] = setting.Service.CaptchaType
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
return
}
- if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ImageCaptcha && !cpt.VerifyReq(ctx.Req) {
- ctx.Data["Err_Captcha"] = true
- ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplLinkAccount, &form)
- return
- }
+ if setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha {
+ var valid bool
+ switch setting.Service.CaptchaType {
+ case setting.ImageCaptcha:
+ valid = cpt.VerifyReq(ctx.Req)
+ case setting.ReCaptcha:
+ valid, _ = recaptcha.Verify(form.GRecaptchaResponse)
+ default:
+ ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
+ return
+ }
- if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ReCaptcha {
- valid, _ := recaptcha.Verify(form.GRecaptchaResponse)
if !valid {
ctx.Data["Err_Captcha"] = true
ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplLinkAccount, &form)
}
}
- if (len(strings.TrimSpace(form.Password)) > 0 || len(strings.TrimSpace(form.Retype)) > 0) && form.Password != form.Retype {
- ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplLinkAccount, &form)
- return
- }
- if len(strings.TrimSpace(form.Password)) > 0 && len(form.Password) < setting.MinPasswordLength {
- ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplLinkAccount, &form)
- return
+ if setting.Service.AllowOnlyExternalRegistration || !setting.Service.RequireExternalRegistrationPassword {
+ // In models.User an empty password is classed as not set, so we set form.Password to empty.
+ // Eventually the database should be changed to indicate "Second Factor"-enabled accounts
+ // (accounts that do not introduce the security vulnerabilities of a password).
+ // If a user decides to circumvent second-factor security, and purposefully create a password,
+ // they can still do so using the "Recover Account" option.
+ form.Password = ""
+ } else {
+ if (len(strings.TrimSpace(form.Password)) > 0 || len(strings.TrimSpace(form.Retype)) > 0) && form.Password != form.Retype {
+ ctx.Data["Err_Password"] = true
+ ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplLinkAccount, &form)
+ return
+ }
+ if len(strings.TrimSpace(form.Password)) > 0 && len(form.Password) < setting.MinPasswordLength {
+ ctx.Data["Err_Password"] = true
+ ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplLinkAccount, &form)
+ return
+ }
}
loginSource, err := models.GetActiveOAuth2LoginSourceByName(gothUser.(goth.User).Provider)
return
}
- if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ImageCaptcha && !cpt.VerifyReq(ctx.Req) {
- ctx.Data["Err_Captcha"] = true
- ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUp, &form)
- return
- }
+ if setting.Service.EnableCaptcha {
+ var valid bool
+ switch setting.Service.CaptchaType {
+ case setting.ImageCaptcha:
+ valid = cpt.VerifyReq(ctx.Req)
+ case setting.ReCaptcha:
+ valid, _ = recaptcha.Verify(form.GRecaptchaResponse)
+ default:
+ ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
+ return
+ }
- if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ReCaptcha {
- valid, _ := recaptcha.Verify(form.GRecaptchaResponse)
if !valid {
ctx.Data["Err_Captcha"] = true
ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUp, &form)
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
ctx.Data["OpenID"] = oid
- if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ImageCaptcha && !cpt.VerifyReq(ctx.Req) {
- ctx.Data["Err_Captcha"] = true
- ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUpOID, &form)
- return
- }
-
- if setting.Service.EnableCaptcha && setting.Service.CaptchaType == setting.ReCaptcha {
- err := ctx.Req.ParseForm()
- if err != nil {
- ctx.ServerError("", err)
+ if setting.Service.EnableCaptcha {
+ var valid bool
+ switch setting.Service.CaptchaType {
+ case setting.ImageCaptcha:
+ valid = cpt.VerifyReq(ctx.Req)
+ case setting.ReCaptcha:
+ err := ctx.Req.ParseForm()
+ if err != nil {
+ ctx.ServerError("", err)
+ return
+ }
+ valid, _ = recaptcha.Verify(form.GRecaptchaResponse)
+ default:
+ ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
return
}
- valid, _ := recaptcha.Verify(form.GRecaptchaResponse)
+
if !valid {
ctx.Data["Err_Captcha"] = true
ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUpOID, &form)
<label for="email">{{.i18n.Tr "email"}}</label>
<input id="email" name="email" type="email" value="{{.email}}" required>
</div>
- <div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
- <label for="password">{{.i18n.Tr "password"}}</label>
- <input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" required>
- </div>
- <div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
- <label for="retype">{{.i18n.Tr "re_type"}}</label>
- <input id="retype" name="retype" type="password" value="{{.retype}}" autocomplete="off" required>
- </div>
+
+ {{if not .DisablePassword}}
+ <div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
+ <label for="password">{{.i18n.Tr "password"}}</label>
+ <input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" required>
+ </div>
+ <div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
+ <label for="retype">{{.i18n.Tr "re_type"}}</label>
+ <input id="retype" name="retype" type="password" value="{{.retype}}" autocomplete="off" required>
+ </div>
+ {{end}}
{{if and .EnableCaptcha (eq .CaptchaType "image")}}
<div class="inline field">
<label></label>