5
5
"compress/gzip"
6
6
"fmt"
7
7
"io"
8
+ "encoding/json"
8
9
"log"
9
10
"net/http"
10
11
"os"
@@ -16,16 +17,20 @@ import (
16
17
"time"
17
18
)
18
19
20
+ type AuthInfo struct {
21
+ Username string
22
+ Password string
23
+ Repositories []string
24
+ }
25
+
19
26
type Service struct {
20
27
Method string
21
28
Handler func (HandlerReq )
22
29
Rpc string
23
30
}
24
31
25
32
type Config struct {
26
- RequireAuth bool
27
- AuthPassEnvVar string
28
- AuthUserEnvVar string
33
+ AuthInfoFilePath string
29
34
DefaultEnv string
30
35
ProjectRoot string
31
36
GitBinPath string
47
52
DefaultAddress = ":8080"
48
53
49
54
DefaultConfig = Config {
50
- RequireAuth : false ,
51
- AuthPassEnvVar : "" ,
52
- AuthUserEnvVar : "" ,
55
+ AuthInfoFilePath : "/tmp/authentication_info_example.json" ,
53
56
DefaultEnv : "" ,
54
57
ProjectRoot : "/tmp" ,
55
58
GitBinPath : "/usr/bin/git" ,
@@ -122,28 +125,46 @@ func serviceRpc(hr HandlerReq) {
122
125
return
123
126
}
124
127
125
- w .Header ().Set ("Content-Type" , fmt .Sprintf ("application/x-git-%s-result" , rpc ))
126
- w .Header ().Set ("Connection" , "Keep-Alive" )
127
- w .Header ().Set ("Transfer-Encoding" , "chunked" )
128
- w .Header ().Set ("X-Content-Type-Options" , "nosniff" )
129
- w .WriteHeader (http .StatusOK )
130
-
131
128
env := os .Environ ()
132
129
133
130
if DefaultConfig .DefaultEnv != "" {
134
131
env = append (env , DefaultConfig .DefaultEnv )
135
132
}
136
133
137
- user , password , authok := r .BasicAuth ()
134
+ username , password , authok := r .BasicAuth ()
135
+ user := FindUser (username )
138
136
if authok {
139
- if DefaultConfig .AuthUserEnvVar != "" {
140
- env = append (env , fmt .Sprintf ("%s=%s" , DefaultConfig .AuthUserEnvVar , user ))
137
+ // Check is user has access to repository
138
+ if user .Username != "" && user .Password != "" {
139
+ requestRepo := strings .Replace (dir , DefaultConfig .ProjectRoot , "" , 1 )
140
+ allow := false
141
+ for _ , repo := range user .Repositories {
142
+ if repo == requestRepo {
143
+ allow = true
144
+ break
145
+ }
146
+ }
147
+
148
+ if ! allow {
149
+ renderNoAccess (w )
150
+ return
151
+ }
152
+ }
153
+
154
+ if user .Username != "" {
155
+ env = append (env , fmt .Sprintf ("%s=%s" , user .Username , username ))
141
156
}
142
- if DefaultConfig . AuthPassEnvVar != "" {
143
- env = append (env , fmt .Sprintf ("%s=%s" , DefaultConfig . AuthPassEnvVar , password ))
157
+ if user . Password != "" {
158
+ env = append (env , fmt .Sprintf ("%s=%s" , user . Password , password ))
144
159
}
145
160
}
146
161
162
+ w .Header ().Set ("Content-Type" , fmt .Sprintf ("application/x-git-%s-result" , rpc ))
163
+ w .Header ().Set ("Connection" , "Keep-Alive" )
164
+ w .Header ().Set ("Transfer-Encoding" , "chunked" )
165
+ w .Header ().Set ("X-Content-Type-Options" , "nosniff" )
166
+ w .WriteHeader (http .StatusOK )
167
+
147
168
args := []string {rpc , "--stateless-rpc" , dir }
148
169
cmd := exec .Command (DefaultConfig .GitBinPath , args ... )
149
170
version := r .Header .Get ("Git-Protocol" )
@@ -214,13 +235,15 @@ func getInfoRefs(hr HandlerReq) {
214
235
access := hasAccess (r , dir , service_name , false )
215
236
version := r .Header .Get ("Git-Protocol" )
216
237
217
- user , password , authok := r .BasicAuth ()
218
- if DefaultConfig .RequireAuth && ! authok {
238
+ username , password , authok := r .BasicAuth ()
239
+ if DefaultConfig .AuthInfoFilePath != "" && ! authok {
219
240
renderAuthRequire (w )
220
241
return
221
242
}
222
243
223
- if authok && user != DefaultConfig .AuthUserEnvVar && password != DefaultConfig .AuthPassEnvVar {
244
+ // Check user credential
245
+ user := FindUser (username )
246
+ if authok && ! (username == user .Username && password == user .Password ) {
224
247
w .WriteHeader (http .StatusUnauthorized )
225
248
return
226
249
}
@@ -244,6 +267,33 @@ func getInfoRefs(hr HandlerReq) {
244
267
}
245
268
}
246
269
270
+ func FindUser (username string ) AuthInfo {
271
+ if username == "" {
272
+ return AuthInfo {}
273
+ }
274
+
275
+ var authInfo []AuthInfo
276
+ var user AuthInfo
277
+ content , err := os .ReadFile (DefaultConfig .AuthInfoFilePath )
278
+ if err != nil {
279
+ log .Print (err )
280
+ }
281
+
282
+ err = json .Unmarshal (content , & authInfo )
283
+ if err != nil {
284
+ log .Print (err )
285
+ }
286
+
287
+ for _ , auth := range authInfo {
288
+ if auth .Username == username {
289
+ user = auth
290
+ break
291
+ }
292
+ }
293
+
294
+ return user
295
+ }
296
+
247
297
func getInfoPacks (hr HandlerReq ) {
248
298
hdrCacheForever (hr .w )
249
299
sendFile ("text/plain; charset=utf-8" , hr )
0 commit comments