@@ -6,6 +6,7 @@ package web
66import (
77 gocontext "context"
88 "net/http"
9+ "strings"
910
1011 "code.gitea.io/gitea/models/perm"
1112 "code.gitea.io/gitea/models/unit"
@@ -19,6 +20,7 @@ import (
1920 "code.gitea.io/gitea/modules/templates"
2021 "code.gitea.io/gitea/modules/validation"
2122 "code.gitea.io/gitea/modules/web"
23+ "code.gitea.io/gitea/modules/web/middleware"
2224 "code.gitea.io/gitea/modules/web/routing"
2325 "code.gitea.io/gitea/routers/common"
2426 "code.gitea.io/gitea/routers/web/admin"
@@ -46,7 +48,7 @@ import (
4648
4749 "gitea.com/go-chi/captcha"
4850 "github.com/NYTimes/gziphandler"
49- "github.com/go-chi/chi/v5/middleware"
51+ chi_middleware "github.com/go-chi/chi/v5/middleware"
5052 "github.com/go-chi/cors"
5153 "github.com/prometheus/client_golang/prometheus"
5254)
@@ -95,6 +97,109 @@ func buildAuthGroup() *auth_service.Group {
9597 return group
9698}
9799
100+ func webAuth (authMethod auth_service.Method ) func (* context.Context ) {
101+ return func (ctx * context.Context ) {
102+ ar , err := common .AuthShared (ctx .Base , ctx .Session , authMethod )
103+ if err != nil {
104+ log .Error ("Failed to verify user: %v" , err )
105+ ctx .Error (http .StatusUnauthorized , "Verify" )
106+ return
107+ }
108+ ctx .Doer = ar .Doer
109+ ctx .IsSigned = ar .Doer != nil
110+ ctx .IsBasicAuth = ar .IsBasicAuth
111+ if ctx .Doer == nil {
112+ // ensure the session uid is deleted
113+ _ = ctx .Session .Delete ("uid" )
114+ }
115+ }
116+ }
117+
118+ // verifyAuthWithOptions checks authentication according to options
119+ func verifyAuthWithOptions (options * common.VerifyOptions ) func (ctx * context.Context ) {
120+ return func (ctx * context.Context ) {
121+ // Check prohibit login users.
122+ if ctx .IsSigned {
123+ if ! ctx .Doer .IsActive && setting .Service .RegisterEmailConfirm {
124+ ctx .Data ["Title" ] = ctx .Tr ("auth.active_your_account" )
125+ ctx .HTML (http .StatusOK , "user/auth/activate" )
126+ return
127+ }
128+ if ! ctx .Doer .IsActive || ctx .Doer .ProhibitLogin {
129+ log .Info ("Failed authentication attempt for %s from %s" , ctx .Doer .Name , ctx .RemoteAddr ())
130+ ctx .Data ["Title" ] = ctx .Tr ("auth.prohibit_login" )
131+ ctx .HTML (http .StatusOK , "user/auth/prohibit_login" )
132+ return
133+ }
134+
135+ if ctx .Doer .MustChangePassword {
136+ if ctx .Req .URL .Path != "/user/settings/change_password" {
137+ if strings .HasPrefix (ctx .Req .UserAgent (), "git" ) {
138+ ctx .Error (http .StatusUnauthorized , ctx .Tr ("auth.must_change_password" ))
139+ return
140+ }
141+ ctx .Data ["Title" ] = ctx .Tr ("auth.must_change_password" )
142+ ctx .Data ["ChangePasscodeLink" ] = setting .AppSubURL + "/user/change_password"
143+ if ctx .Req .URL .Path != "/user/events" {
144+ middleware .SetRedirectToCookie (ctx .Resp , setting .AppSubURL + ctx .Req .URL .RequestURI ())
145+ }
146+ ctx .Redirect (setting .AppSubURL + "/user/settings/change_password" )
147+ return
148+ }
149+ } else if ctx .Req .URL .Path == "/user/settings/change_password" {
150+ // make sure that the form cannot be accessed by users who don't need this
151+ ctx .Redirect (setting .AppSubURL + "/" )
152+ return
153+ }
154+ }
155+
156+ // Redirect to dashboard (or alternate location) if user tries to visit any non-login page.
157+ if options .SignOutRequired && ctx .IsSigned && ctx .Req .URL .RequestURI () != "/" {
158+ ctx .RedirectToFirst (ctx .FormString ("redirect_to" ))
159+ return
160+ }
161+
162+ if ! options .SignOutRequired && ! options .DisableCSRF && ctx .Req .Method == "POST" {
163+ ctx .Csrf .Validate (ctx )
164+ if ctx .Written () {
165+ return
166+ }
167+ }
168+
169+ if options .SignInRequired {
170+ if ! ctx .IsSigned {
171+ if ctx .Req .URL .Path != "/user/events" {
172+ middleware .SetRedirectToCookie (ctx .Resp , setting .AppSubURL + ctx .Req .URL .RequestURI ())
173+ }
174+ ctx .Redirect (setting .AppSubURL + "/user/login" )
175+ return
176+ } else if ! ctx .Doer .IsActive && setting .Service .RegisterEmailConfirm {
177+ ctx .Data ["Title" ] = ctx .Tr ("auth.active_your_account" )
178+ ctx .HTML (http .StatusOK , "user/auth/activate" )
179+ return
180+ }
181+ }
182+
183+ // Redirect to log in page if auto-signin info is provided and has not signed in.
184+ if ! options .SignOutRequired && ! ctx .IsSigned &&
185+ len (ctx .GetSiteCookie (setting .CookieUserName )) > 0 {
186+ if ctx .Req .URL .Path != "/user/events" {
187+ middleware .SetRedirectToCookie (ctx .Resp , setting .AppSubURL + ctx .Req .URL .RequestURI ())
188+ }
189+ ctx .Redirect (setting .AppSubURL + "/user/login" )
190+ return
191+ }
192+
193+ if options .AdminRequired {
194+ if ! ctx .Doer .IsAdmin {
195+ ctx .Error (http .StatusForbidden )
196+ return
197+ }
198+ ctx .Data ["PageIsAdmin" ] = true
199+ }
200+ }
201+ }
202+
98203func ctxDataSet (args ... any ) func (ctx * context.Context ) {
99204 return func (ctx * context.Context ) {
100205 for i := 0 ; i < len (args ); i += 2 {
@@ -144,10 +249,10 @@ func Routes() *web.Route {
144249 mid = append (mid , common .Sessioner (), context .Contexter ())
145250
146251 // Get user from session if logged in.
147- mid = append (mid , auth_service . Auth (buildAuthGroup ()))
252+ mid = append (mid , webAuth (buildAuthGroup ()))
148253
149254 // GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route
150- mid = append (mid , middleware .GetHead )
255+ mid = append (mid , chi_middleware .GetHead )
151256
152257 if setting .API .EnableSwagger {
153258 // Note: The route is here but no in API routes because it renders a web page
@@ -168,12 +273,12 @@ func Routes() *web.Route {
168273
169274// registerRoutes register routes
170275func registerRoutes (m * web.Route ) {
171- reqSignIn := auth_service . VerifyAuthWithOptions ( & auth_service .VerifyOptions {SignInRequired : true })
172- reqSignOut := auth_service . VerifyAuthWithOptions ( & auth_service .VerifyOptions {SignOutRequired : true })
276+ reqSignIn := verifyAuthWithOptions ( & common .VerifyOptions {SignInRequired : true })
277+ reqSignOut := verifyAuthWithOptions ( & common .VerifyOptions {SignOutRequired : true })
173278 // TODO: rename them to "optSignIn", which means that the "sign-in" could be optional, depends on the VerifyOptions (RequireSignInView)
174- ignSignIn := auth_service . VerifyAuthWithOptions ( & auth_service .VerifyOptions {SignInRequired : setting .Service .RequireSignInView })
175- ignExploreSignIn := auth_service . VerifyAuthWithOptions ( & auth_service .VerifyOptions {SignInRequired : setting .Service .RequireSignInView || setting .Service .Explore .RequireSigninView })
176- ignSignInAndCsrf := auth_service . VerifyAuthWithOptions ( & auth_service .VerifyOptions {DisableCSRF : true })
279+ ignSignIn := verifyAuthWithOptions ( & common .VerifyOptions {SignInRequired : setting .Service .RequireSignInView })
280+ ignExploreSignIn := verifyAuthWithOptions ( & common .VerifyOptions {SignInRequired : setting .Service .RequireSignInView || setting .Service .Explore .RequireSigninView })
281+ ignSignInAndCsrf := verifyAuthWithOptions ( & common .VerifyOptions {DisableCSRF : true })
177282 validation .AddBindingRules ()
178283
179284 linkAccountEnabled := func (ctx * context.Context ) {
@@ -543,7 +648,7 @@ func registerRoutes(m *web.Route) {
543648
544649 m .Get ("/avatar/{hash}" , user .AvatarByEmailHash )
545650
546- adminReq := auth_service . VerifyAuthWithOptions ( & auth_service .VerifyOptions {SignInRequired : true , AdminRequired : true })
651+ adminReq := verifyAuthWithOptions ( & common .VerifyOptions {SignInRequired : true , AdminRequired : true })
547652
548653 // ***** START: Admin *****
549654 m .Group ("/admin" , func () {
0 commit comments