55 "compress/gzip"
66 "fmt"
77 "io"
8+ "encoding/json"
89 "log"
910 "net/http"
1011 "os"
@@ -16,16 +17,20 @@ import (
1617 "time"
1718)
1819
20+ type AuthInfo struct {
21+ Username string
22+ Password string
23+ Repositories []string
24+ }
25+
1926type Service struct {
2027 Method string
2128 Handler func (HandlerReq )
2229 Rpc string
2330}
2431
2532type Config struct {
26- RequireAuth bool
27- AuthPassEnvVar string
28- AuthUserEnvVar string
33+ AuthInfoFilePath string
2934 DefaultEnv string
3035 ProjectRoot string
3136 GitBinPath string
4752 DefaultAddress = ":8080"
4853
4954 DefaultConfig = Config {
50- RequireAuth : false ,
51- AuthPassEnvVar : "" ,
52- AuthUserEnvVar : "" ,
55+ AuthInfoFilePath : "/tmp/authentication_info_example.json" ,
5356 DefaultEnv : "" ,
5457 ProjectRoot : "/tmp" ,
5558 GitBinPath : "/usr/bin/git" ,
@@ -122,28 +125,46 @@ func serviceRpc(hr HandlerReq) {
122125 return
123126 }
124127
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-
131128 env := os .Environ ()
132129
133130 if DefaultConfig .DefaultEnv != "" {
134131 env = append (env , DefaultConfig .DefaultEnv )
135132 }
136133
137- user , password , authok := r .BasicAuth ()
134+ username , password , authok := r .BasicAuth ()
135+ user := FindUser (username )
138136 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 ))
141156 }
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 ))
144159 }
145160 }
146161
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+
147168 args := []string {rpc , "--stateless-rpc" , dir }
148169 cmd := exec .Command (DefaultConfig .GitBinPath , args ... )
149170 version := r .Header .Get ("Git-Protocol" )
@@ -214,13 +235,15 @@ func getInfoRefs(hr HandlerReq) {
214235 access := hasAccess (r , dir , service_name , false )
215236 version := r .Header .Get ("Git-Protocol" )
216237
217- user , password , authok := r .BasicAuth ()
218- if DefaultConfig .RequireAuth && ! authok {
238+ username , password , authok := r .BasicAuth ()
239+ if DefaultConfig .AuthInfoFilePath != "" && ! authok {
219240 renderAuthRequire (w )
220241 return
221242 }
222243
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 ) {
224247 w .WriteHeader (http .StatusUnauthorized )
225248 return
226249 }
@@ -244,6 +267,33 @@ func getInfoRefs(hr HandlerReq) {
244267 }
245268}
246269
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+
247297func getInfoPacks (hr HandlerReq ) {
248298 hdrCacheForever (hr .w )
249299 sendFile ("text/plain; charset=utf-8" , hr )
0 commit comments