Skip to content

Commit 6526733

Browse files
lunnywxiaoguang
andauthored
Let web and API routes have different auth methods group (#19168)
* remove the global methods but create dynamiclly * Fix lint * Fix windows lint * Fix windows lint * some improvements Co-authored-by: wxiaoguang <[email protected]>
1 parent d6fa138 commit 6526733

File tree

10 files changed

+140
-80
lines changed

10 files changed

+140
-80
lines changed

routers/api/v1/api.go

+26-1
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,26 @@ func bind(obj interface{}) http.HandlerFunc {
563563
})
564564
}
565565

566+
// The OAuth2 plugin is expected to be executed first, as it must ignore the user id stored
567+
// in the session (if there is a user id stored in session other plugins might return the user
568+
// object for that id).
569+
//
570+
// The Session plugin is expected to be executed second, in order to skip authentication
571+
// for users that have already signed in.
572+
func buildAuthGroup() *auth.Group {
573+
group := auth.NewGroup(
574+
&auth.OAuth2{},
575+
&auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API
576+
auth.SharedSession, // FIXME: this should be removed once all UI don't reference API/v1, see https://github.com/go-gitea/gitea/pull/16052
577+
)
578+
if setting.Service.EnableReverseProxyAuth {
579+
group.Add(&auth.ReverseProxy{})
580+
}
581+
specialAdd(group)
582+
583+
return group
584+
}
585+
566586
// Routes registers all v1 APIs routes to web application.
567587
func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
568588
m := web.NewRoute()
@@ -583,8 +603,13 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
583603
}
584604
m.Use(context.APIContexter())
585605

606+
group := buildAuthGroup()
607+
if err := group.Init(); err != nil {
608+
log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err)
609+
}
610+
586611
// Get user from session if logged in.
587-
m.Use(context.APIAuth(auth.NewGroup(auth.Methods()...)))
612+
m.Use(context.APIAuth(group))
588613

589614
m.Use(context.ToggleAPI(&context.ToggleOptions{
590615
SignInRequired: setting.Service.RequireSignInView,

routers/api/v1/auth.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build !windows
6+
// +build !windows
7+
8+
package v1
9+
10+
import auth_service "code.gitea.io/gitea/services/auth"
11+
12+
func specialAdd(group *auth_service.Group) {}

routers/api/v1/auth_windows.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package v1
6+
7+
import (
8+
"code.gitea.io/gitea/models/auth"
9+
auth_service "code.gitea.io/gitea/services/auth"
10+
)
11+
12+
// specialAdd registers the SSPI auth method as the last method in the list.
13+
// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation
14+
// fails (or if negotiation should continue), which would prevent other authentication methods
15+
// to execute at all.
16+
func specialAdd(group *auth_service.Group) {
17+
if auth.IsSSPIEnabled() {
18+
group.Add(&auth_service.SSPI{})
19+
}
20+
}

routers/web/auth.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build !windows
6+
// +build !windows
7+
8+
package web
9+
10+
import auth_service "code.gitea.io/gitea/services/auth"
11+
12+
func specialAdd(group *auth_service.Group) {}

routers/web/auth_windows.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package web
6+
7+
import (
8+
"code.gitea.io/gitea/models/auth"
9+
auth_service "code.gitea.io/gitea/services/auth"
10+
)
11+
12+
// specialAdd registers the SSPI auth method as the last method in the list.
13+
// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation
14+
// fails (or if negotiation should continue), which would prevent other authentication methods
15+
// to execute at all.
16+
func specialAdd(group *auth_service.Group) {
17+
if auth.IsSSPIEnabled() {
18+
group.Add(&auth_service.SSPI{})
19+
}
20+
}

routers/web/web.go

+26-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,26 @@ func CorsHandler() func(next http.Handler) http.Handler {
7373
}
7474
}
7575

76+
// The OAuth2 plugin is expected to be executed first, as it must ignore the user id stored
77+
// in the session (if there is a user id stored in session other plugins might return the user
78+
// object for that id).
79+
//
80+
// The Session plugin is expected to be executed second, in order to skip authentication
81+
// for users that have already signed in.
82+
func buildAuthGroup() *auth_service.Group {
83+
group := auth_service.NewGroup(
84+
&auth_service.OAuth2{}, // FIXME: this should be removed and only applied in download and oauth realted routers
85+
&auth_service.Basic{}, // FIXME: this should be removed and only applied in download and git/lfs routers
86+
auth_service.SharedSession,
87+
)
88+
if setting.Service.EnableReverseProxyAuth {
89+
group.Add(&auth_service.ReverseProxy{})
90+
}
91+
specialAdd(group)
92+
93+
return group
94+
}
95+
7696
// Routes returns all web routes
7797
func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
7898
routes := web.NewRoute()
@@ -160,8 +180,13 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
160180
// Removed: toolbox.Toolboxer middleware will provide debug information which seems unnecessary
161181
common = append(common, context.Contexter())
162182

183+
group := buildAuthGroup()
184+
if err := group.Init(); err != nil {
185+
log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err)
186+
}
187+
163188
// Get user from session if logged in.
164-
common = append(common, context.Auth(auth_service.NewGroup(auth_service.Methods()...)))
189+
common = append(common, context.Auth(group))
165190

166191
// GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route
167192
common = append(common, middleware.GetHead)

services/auth/auth.go

+4-58
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package auth
88
import (
99
"fmt"
1010
"net/http"
11-
"reflect"
1211
"regexp"
1312
"strings"
1413

@@ -21,75 +20,22 @@ import (
2120
"code.gitea.io/gitea/modules/web/middleware"
2221
)
2322

24-
// authMethods contains the list of authentication plugins in the order they are expected to be
25-
// executed.
26-
//
27-
// The OAuth2 plugin is expected to be executed first, as it must ignore the user id stored
28-
// in the session (if there is a user id stored in session other plugins might return the user
29-
// object for that id).
30-
//
31-
// The Session plugin is expected to be executed second, in order to skip authentication
32-
// for users that have already signed in.
33-
var authMethods = []Method{
34-
&OAuth2{},
35-
&Basic{},
36-
&Session{},
37-
}
38-
3923
// The purpose of the following three function variables is to let the linter know that
4024
// those functions are not dead code and are actually being used
4125
var (
4226
_ = handleSignIn
43-
)
44-
45-
// Methods returns the instances of all registered methods
46-
func Methods() []Method {
47-
return authMethods
48-
}
4927

50-
// Register adds the specified instance to the list of available methods
51-
func Register(method Method) {
52-
authMethods = append(authMethods, method)
53-
}
28+
// SharedSession the session auth should only be used by web, but now both web and API/v1
29+
// will use it. We can remove this after Web removed dependent API/v1
30+
SharedSession = &Session{}
31+
)
5432

5533
// Init should be called exactly once when the application starts to allow plugins
5634
// to allocate necessary resources
5735
func Init() {
58-
if setting.Service.EnableReverseProxyAuth {
59-
Register(&ReverseProxy{})
60-
}
61-
specialInit()
62-
for _, method := range Methods() {
63-
initializable, ok := method.(Initializable)
64-
if !ok {
65-
continue
66-
}
67-
68-
err := initializable.Init()
69-
if err != nil {
70-
log.Error("Could not initialize '%s' auth method, error: %s", reflect.TypeOf(method).String(), err)
71-
}
72-
}
73-
7436
webauthn.Init()
7537
}
7638

77-
// Free should be called exactly once when the application is terminating to allow Auth plugins
78-
// to release necessary resources
79-
func Free() {
80-
for _, method := range Methods() {
81-
freeable, ok := method.(Freeable)
82-
if !ok {
83-
continue
84-
}
85-
86-
err := freeable.Free()
87-
if err != nil {
88-
log.Error("Could not free '%s' auth method, error: %s", reflect.TypeOf(method).String(), err)
89-
}
90-
}
91-
}
92-
9339
// isAttachmentDownload check if request is a file download (GET) with URL to an attachment
9440
func isAttachmentDownload(req *http.Request) bool {
9541
return strings.HasPrefix(req.URL.Path, "/attachments/") && req.Method == "GET"

services/auth/group.go

+20
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package auth
66

77
import (
88
"net/http"
9+
"reflect"
10+
"strings"
911

1012
"code.gitea.io/gitea/models/db"
1113
user_model "code.gitea.io/gitea/models/user"
@@ -30,6 +32,24 @@ func NewGroup(methods ...Method) *Group {
3032
}
3133
}
3234

35+
// Add adds a new method to group
36+
func (b *Group) Add(method Method) {
37+
b.methods = append(b.methods, method)
38+
}
39+
40+
// Name returns group's methods name
41+
func (b *Group) Name() string {
42+
names := make([]string, 0, len(b.methods))
43+
for _, m := range b.methods {
44+
if n, ok := m.(Named); ok {
45+
names = append(names, n.Name())
46+
} else {
47+
names = append(names, reflect.TypeOf(m).Elem().Name())
48+
}
49+
}
50+
return strings.Join(names, ",")
51+
}
52+
3353
// Init does nothing as the Basic implementation does not need to allocate any resources
3454
func (b *Group) Init() error {
3555
for _, method := range b.methods {

services/auth/placeholder.go

-10
This file was deleted.

services/auth/sspi_windows.go

-10
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,3 @@ func sanitizeUsername(username string, cfg *sspi.Source) string {
244244
username = replaceSeparators(username, cfg)
245245
return username
246246
}
247-
248-
// specialInit registers the SSPI auth method as the last method in the list.
249-
// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation
250-
// fails (or if negotiation should continue), which would prevent other authentication methods
251-
// to execute at all.
252-
func specialInit() {
253-
if auth.IsSSPIEnabled() {
254-
Register(&SSPI{})
255-
}
256-
}

0 commit comments

Comments
 (0)