Skip to content

Commit 7ffd745

Browse files
committed
fix
1 parent 5015992 commit 7ffd745

File tree

8 files changed

+44
-2
lines changed

8 files changed

+44
-2
lines changed

custom/conf/app.example.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,9 @@ INTERNAL_TOKEN =
518518
;;
519519
;; On user registration, record the IP address and user agent of the user to help identify potential abuse.
520520
;; RECORD_USER_SIGNUP_METADATA = false
521+
;;
522+
;; Force users to enroll into Two-Factor Authentication. Users without 2FA have no access to any repositories.
523+
;ENFORCE_TWO_FACTOR_AUTH = false
521524

522525
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
523526
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

modules/session/key.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package session
2+
3+
const (
4+
KeyUID = "uid"
5+
KeyUname = "uname"
6+
KeyTwofaSatisfied = "twofaSatisfied"
7+
)

modules/setting/security.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ var (
3939
CSRFCookieName = "_csrf"
4040
CSRFCookieHTTPOnly = true
4141
RecordUserSignupMetadata = false
42+
EnforceTwoFactorAuth = false
4243
)
4344

4445
// loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set
@@ -141,6 +142,7 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
141142
CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true)
142143
PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false)
143144
SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20)
145+
EnforceTwoFactorAuth = sec.Key("ENFORCE_TWO_FACTOR_AUTH").MustBool(false)
144146

145147
InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN")
146148
if InstallLock && InternalToken == "" {

options/locale/locale_en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ use_scratch_code = Use a scratch code
449449
twofa_scratch_used = You have used your scratch code. You have been redirected to the two-factor settings page so you may remove your device enrollment or generate a new scratch code.
450450
twofa_passcode_incorrect = Your passcode is incorrect. If you misplaced your device, use your scratch code to sign in.
451451
twofa_scratch_token_incorrect = Your scratch code is incorrect.
452+
twofa_required = You must setup Two-Factor Authentication to get access to repositories
452453
login_userpass = Sign In
453454
login_openid = OpenID
454455
oauth_signup_tab = Register New Account

routers/web/auth/auth.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,13 @@ func autoSignIn(ctx *context.Context) (bool, error) {
8686

8787
ctx.SetSiteCookie(setting.CookieRememberName, nt.ID+":"+token, setting.LogInRememberDays*timeutil.Day)
8888

89+
twofa, _ := auth.GetTwoFactorByUID(ctx, u.ID)
8990
if err := updateSession(ctx, nil, map[string]any{
9091
// Set session IDs
9192
"uid": u.ID,
9293
"uname": u.Name,
94+
95+
session.KeyTwofaSatisfied: twofa != nil,
9396
}); err != nil {
9497
return false, fmt.Errorf("unable to updateSession: %w", err)
9598
}

routers/web/user/setting/security/2fa.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package security
66

77
import (
88
"bytes"
9+
"code.gitea.io/gitea/modules/session"
910
"encoding/base64"
1011
"html/template"
1112
"image/png"
@@ -163,12 +164,21 @@ func EnrollTwoFactor(ctx *context.Context) {
163164

164165
ctx.Data["Title"] = ctx.Tr("settings")
165166
ctx.Data["PageIsSettingsSecurity"] = true
167+
ctx.Data["ShowTwoFactorRequiredMessage"] = false
166168

167169
t, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID)
168170
if t != nil {
169171
// already enrolled - we should redirect back!
170172
log.Warn("Trying to re-enroll %-v in twofa when already enrolled", ctx.Doer)
171173
ctx.Flash.Error(ctx.Tr("settings.twofa_is_enrolled"))
174+
175+
if ctx.Session.Get(session.KeyTwofaSatisfied) == nil {
176+
// in case a 2FA user is using an old session (the session doesn't know 2FA authed),
177+
// he will be navigated to this page, we should update the session status
178+
_ = ctx.Session.Set(session.KeyTwofaSatisfied, true)
179+
_ = ctx.Session.Release()
180+
}
181+
172182
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
173183
return
174184
}
@@ -194,6 +204,7 @@ func EnrollTwoFactorPost(ctx *context.Context) {
194204
form := web.GetForm(ctx).(*forms.TwoFactorAuthForm)
195205
ctx.Data["Title"] = ctx.Tr("settings")
196206
ctx.Data["PageIsSettingsSecurity"] = true
207+
ctx.Data["ShowTwoFactorRequiredMessage"] = false
197208

198209
t, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID)
199210
if t != nil {
@@ -246,6 +257,12 @@ func EnrollTwoFactorPost(ctx *context.Context) {
246257
return
247258
}
248259

260+
newTwoFactorErr := auth.NewTwoFactor(ctx, t)
261+
if newTwoFactorErr == nil {
262+
if err := ctx.Session.Set(session.KeyTwofaSatisfied, true); err != nil {
263+
log.Error("Unable to set %s to session: Error: %v", session.KeyTwofaSatisfied, err)
264+
}
265+
}
249266
// Now we have to delete the secrets - because if we fail to insert then it's highly likely that they have already been used
250267
// If we can detect the unique constraint failure below we can move this to after the NewTwoFactor
251268
if err := ctx.Session.Delete("twofaSecret"); err != nil {
@@ -261,10 +278,10 @@ func EnrollTwoFactorPost(ctx *context.Context) {
261278
log.Error("Unable to save changes to the session: %v", err)
262279
}
263280

264-
if err = auth.NewTwoFactor(ctx, t); err != nil {
281+
if newTwoFactorErr != nil {
265282
// FIXME: We need to handle a unique constraint fail here it's entirely possible that another request has beaten us.
266283
// If there is a unique constraint fail we should just tolerate the error
267-
ctx.ServerError("SettingsTwoFactor: Failed to save two factor", err)
284+
ctx.ServerError("SettingsTwoFactor: Failed to save two factor", newTwoFactorErr)
268285
return
269286
}
270287

services/context/context.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ func Contexter() func(next http.Handler) http.Handler {
196196

197197
ctx.Data["SystemConfig"] = setting.Config()
198198

199+
ctx.Data["ShowTwoFactorRequiredMessage"] = setting.EnforceTwoFactorAuth &&
200+
ctx.Session.Get("uid") != nil &&
201+
ctx.Session.Get(session.KeyTwofaSatisfied) != true
202+
199203
// FIXME: do we really always need these setting? There should be someway to have to avoid having to always set these
200204
ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
201205
ctx.Data["DisableStars"] = setting.Repository.DisableStars

templates/base/alert.tmpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@
1818
<p>{{.Flash.WarningMsg | SanitizeHTML}}</p>
1919
</div>
2020
{{- end -}}
21+
{{- if .ShowTwoFactorRequiredMessage -}}
22+
<div class="ui negative message flash-message flash-error">
23+
<p><a href="{{AppSubUrl}}/user/settings/security/two_factor/enroll">{{ctx.Locale.Tr "auth.twofa_required"}} &raquo;</a></p>
24+
</div>
25+
{{- end -}}

0 commit comments

Comments
 (0)