@@ -7,17 +7,19 @@ package sso
7
7
import (
8
8
"errors"
9
9
"net/http"
10
+ "reflect"
10
11
"strings"
11
12
12
13
"code.gitea.io/gitea/models"
13
14
"code.gitea.io/gitea/modules/base"
14
15
"code.gitea.io/gitea/modules/log"
15
16
"code.gitea.io/gitea/modules/setting"
16
- "code.gitea.io/gitea/modules/templates"
17
+
18
+ "gitea.com/macaron/macaron"
19
+ "gitea.com/macaron/session"
17
20
18
21
gouuid "github.com/google/uuid"
19
22
"github.com/quasoft/websspi"
20
- "github.com/unrolled/render"
21
23
)
22
24
23
25
const (
@@ -39,26 +41,14 @@ var (
39
41
// On successful authentication returns a valid user object.
40
42
// Returns nil if authentication fails.
41
43
type SSPI struct {
42
- rnd * render.Render
43
44
}
44
45
45
46
// Init creates a new global websspi.Authenticator object
46
47
func (s * SSPI ) Init () error {
47
48
config := websspi .NewConfig ()
48
49
var err error
49
50
sspiAuth , err = websspi .New (config )
50
- if err != nil {
51
- return err
52
- }
53
- s .rnd = render .New (render.Options {
54
- Extensions : []string {".tmpl" },
55
- Directory : "templates" ,
56
- Funcs : templates .NewFuncMap (),
57
- Asset : templates .GetAsset ,
58
- AssetNames : templates .GetAssetNames ,
59
- IsDevelopment : setting .RunMode != "prod" ,
60
- })
61
- return nil
51
+ return err
62
52
}
63
53
64
54
// Free releases resources used by the global websspi.Authenticator object
@@ -75,8 +65,8 @@ func (s *SSPI) IsEnabled() bool {
75
65
// If authentication is successful, returs the corresponding user object.
76
66
// If negotiation should continue or authentication fails, immediately returns a 401 HTTP
77
67
// response code, as required by the SPNEGO protocol.
78
- func (s * SSPI ) VerifyAuthData (req * http.Request , w http. ResponseWriter , store DataStore , sess SessionStore ) * models.User {
79
- if ! s .shouldAuthenticate (req ) {
68
+ func (s * SSPI ) VerifyAuthData (req * http.Request , store DataStore , sess SessionStore ) * models.User {
69
+ if ! s .shouldAuthenticate (ctx ) {
80
70
return nil
81
71
}
82
72
@@ -86,29 +76,22 @@ func (s *SSPI) VerifyAuthData(req *http.Request, w http.ResponseWriter, store Da
86
76
return nil
87
77
}
88
78
89
- userInfo , outToken , err := sspiAuth .Authenticate (req , w )
79
+ userInfo , outToken , err := sspiAuth .Authenticate (req , ctx . Resp )
90
80
if err != nil {
91
81
log .Warn ("Authentication failed with error: %v\n " , err )
92
- sspiAuth .AppendAuthenticateHeader (w , outToken )
82
+ sspiAuth .AppendAuthenticateHeader (ctx . Resp , outToken )
93
83
94
84
// Include the user login page in the 401 response to allow the user
95
85
// to login with another authentication method if SSPI authentication
96
86
// fails
97
- store .GetData ()["Flash" ] = map [string ]string {
98
- "ErrMsg" : err .Error (),
99
- }
100
- store .GetData ()["EnableOpenIDSignIn" ] = setting .Service .EnableOpenIDSignIn
101
- store .GetData ()["EnableSSPI" ] = true
102
-
103
- err := s .rnd .HTML (w , 401 , string (tplSignIn ), templates .BaseVars ().Merge (store .GetData ()))
104
- if err != nil {
105
- log .Error ("%v" , err )
106
- }
107
-
87
+ addFlashErr (ctx , ctx .Tr ("auth.sspi_auth_failed" ))
88
+ ctx .Data ["EnableOpenIDSignIn" ] = setting .Service .EnableOpenIDSignIn
89
+ ctx .Data ["EnableSSPI" ] = true
90
+ ctx .HTML (401 , string (tplSignIn ))
108
91
return nil
109
92
}
110
93
if outToken != "" {
111
- sspiAuth .AppendAuthenticateHeader (w , outToken )
94
+ sspiAuth .AppendAuthenticateHeader (ctx . Resp , outToken )
112
95
}
113
96
114
97
username := sanitizeUsername (userInfo .Username , cfg )
@@ -127,16 +110,16 @@ func (s *SSPI) VerifyAuthData(req *http.Request, w http.ResponseWriter, store Da
127
110
log .Error ("User '%s' not found" , username )
128
111
return nil
129
112
}
130
- user , err = s .newUser (username , cfg )
113
+ user , err = s .newUser (ctx , username , cfg )
131
114
if err != nil {
132
115
log .Error ("CreateUser: %v" , err )
133
116
return nil
134
117
}
135
118
}
136
119
137
120
// Make sure requests to API paths and PWA resources do not create a new session
138
- if ! isAPIPath (req ) && ! isAttachmentDownload (req ) {
139
- handleSignIn (w , req , sess , user )
121
+ if ! isAPIPath (ctx ) && ! isAttachmentDownload (ctx ) {
122
+ handleSignIn (ctx , sess , user )
140
123
}
141
124
142
125
return user
@@ -163,7 +146,7 @@ func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) {
163
146
if path == "/user/login" {
164
147
if req .FormValue ("user_name" ) != "" && req .FormValue ("password" ) != "" {
165
148
shouldAuth = false
166
- } else if req .FormValue ("auth_with_sspi" ) == "1" {
149
+ } else if ctx . Req .FormValue ("auth_with_sspi" ) == "1" {
167
150
shouldAuth = true
168
151
}
169
152
} else if isInternalPath (req ) {
@@ -234,6 +217,20 @@ func sanitizeUsername(username string, cfg *models.SSPIConfig) string {
234
217
return username
235
218
}
236
219
220
+ // addFlashErr adds an error message to the Flash object mapped to a macaron.Context
221
+ func addFlashErr (ctx * macaron.Context , err string ) {
222
+ fv := ctx .GetVal (reflect .TypeOf (& session.Flash {}))
223
+ if ! fv .IsValid () {
224
+ return
225
+ }
226
+ flash , ok := fv .Interface ().(* session.Flash )
227
+ if ! ok {
228
+ return
229
+ }
230
+ flash .Error (err )
231
+ ctx .Data ["Flash" ] = flash
232
+ }
233
+
237
234
// init registers the SSPI auth method as the last method in the list.
238
235
// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation
239
236
// fails (or if negotiation should continue), which would prevent other authentication methods
0 commit comments