Skip to content

Commit face41c

Browse files
committed
fix
1 parent e481638 commit face41c

File tree

9 files changed

+68
-75
lines changed

9 files changed

+68
-75
lines changed

routers/api/v1/api.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,10 @@ func buildAuthGroup() *auth.Group {
705705
if setting.Service.EnableReverseProxyAuthAPI {
706706
group.Add(&auth.ReverseProxy{})
707707
}
708-
specialAdd(group)
708+
709+
if setting.IsWindows && auth_model.IsSSPIEnabled() {
710+
group.Add(&auth.SSPI{}) // it MUST be the last, see the comment of SSPI
711+
}
709712

710713
return group
711714
}

routers/api/v1/auth.go

Lines changed: 0 additions & 10 deletions
This file was deleted.

routers/api/v1/auth_windows.go

Lines changed: 0 additions & 19 deletions
This file was deleted.

routers/web/auth.go

Lines changed: 0 additions & 10 deletions
This file was deleted.

routers/web/auth_windows.go

Lines changed: 0 additions & 19 deletions
This file was deleted.

routers/web/web.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99
"strings"
1010

11+
auth_model "code.gitea.io/gitea/models/auth"
1112
"code.gitea.io/gitea/models/perm"
1213
"code.gitea.io/gitea/models/unit"
1314
"code.gitea.io/gitea/modules/context"
@@ -92,7 +93,10 @@ func buildAuthGroup() *auth_service.Group {
9293
if setting.Service.EnableReverseProxyAuth {
9394
group.Add(&auth_service.ReverseProxy{})
9495
}
95-
specialAdd(group)
96+
97+
if setting.IsWindows && auth_model.IsSSPIEnabled() {
98+
group.Add(&auth_service.SSPI{}) // it MUST be the last, see the comment of SSPI
99+
}
96100

97101
return group
98102
}

services/auth/sspi_windows.go renamed to services/auth/sspi.go

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,19 @@ import (
2121
"code.gitea.io/gitea/services/auth/source/sspi"
2222

2323
gouuid "github.com/google/uuid"
24-
"github.com/quasoft/websspi"
2524
)
2625

2726
const (
2827
tplSignIn base.TplName = "user/auth/signin"
2928
)
3029

30+
type SSPIAuth interface {
31+
AppendAuthenticateHeader(w http.ResponseWriter, data string)
32+
Authenticate(r *http.Request, w http.ResponseWriter) (userInfo *UserInfo, outToken string, err error)
33+
}
34+
3135
var (
32-
// sspiAuth is a global instance of the websspi authentication package,
33-
// which is used to avoid acquiring the server credential handle on
34-
// every request
35-
sspiAuth *websspi.Authenticator
36+
sspiAuth SSPIAuth // a global instance of the websspi authenticator to avoid acquiring the server credential handle on every request
3637
sspiAuthOnce sync.Once
3738

3839
// Ensure the struct implements the interface.
@@ -41,8 +42,9 @@ var (
4142

4243
// SSPI implements the SingleSignOn interface and authenticates requests
4344
// via the built-in SSPI module in Windows for SPNEGO authentication.
44-
// On successful authentication returns a valid user object.
45-
// Returns nil if authentication fails.
45+
// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation
46+
// fails (or if negotiation should continue), which would prevent other authentication methods
47+
// to execute at all.
4648
type SSPI struct{}
4749

4850
// Name represents the name of auth method
@@ -55,14 +57,7 @@ func (s *SSPI) Name() string {
5557
// If negotiation should continue or authentication fails, immediately returns a 401 HTTP
5658
// response code, as required by the SPNEGO protocol.
5759
func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
58-
var errInit error
59-
sspiAuthOnce.Do(func() {
60-
config := websspi.NewConfig()
61-
sspiAuth, errInit = websspi.New(config)
62-
})
63-
if errInit != nil {
64-
return nil, errInit
65-
}
60+
sspiAuthOnce.Do(sspiAuthInit)
6661

6762
if !s.shouldAuthenticate(req) {
6863
return nil, nil

services/auth/sspiauth_posix.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
//go:build !windows
5+
6+
package auth
7+
8+
import (
9+
"errors"
10+
"net/http"
11+
)
12+
13+
type UserInfo struct {
14+
Username string // Name of user, usually in the form DOMAIN\User
15+
Groups []string // The global groups the user is a member of
16+
}
17+
18+
type sspiAuthMock struct{}
19+
20+
func (s sspiAuthMock) AppendAuthenticateHeader(w http.ResponseWriter, data string) {
21+
}
22+
23+
func (s sspiAuthMock) Authenticate(r *http.Request, w http.ResponseWriter) (userInfo *UserInfo, outToken string, err error) {
24+
return nil, "", errors.New("not implemented")
25+
}
26+
27+
func sspiAuthInit() {
28+
sspiAuth = &sspiAuthMock{} // TODO: we can mock the SSPI auth in tests
29+
}

services/auth/sspiauth_windows.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
//go:build windows
5+
6+
package auth
7+
8+
import (
9+
"github.com/quasoft/websspi"
10+
)
11+
12+
type UserInfo = websspi.UserInfo
13+
14+
func sspiAuthInit() {
15+
var err error
16+
config := websspi.NewConfig()
17+
if sspiAuth, err = websspi.New(config); err != nil {
18+
panic(err) // this init is called by a sync.Once, maybe "panic" is the simplest way to handle errors
19+
}
20+
}

0 commit comments

Comments
 (0)