Skip to content

Commit ff64503

Browse files
author
navetacandra
committed
feat: authentication with auth data stored in file
1 parent 56425e7 commit ff64503

File tree

4 files changed

+90
-29
lines changed

4 files changed

+90
-29
lines changed

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,8 @@ Flags
3333

3434
```
3535
Usage of ./git-http-backend:
36-
-require_auth bool
37-
set require auth enable/disable
38-
-auth_pass_env_var string
39-
set an env var to provide the basic auth pass as
40-
-auth_user_env_var string
41-
set an env var to provide the basic auth user as
36+
-auth_data string
37+
set auth info data path
4238
-default_env string
4339
set the default env
4440
-git_bin_path string

authentication_info_example.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[
2+
{
3+
"Username": "user1",
4+
"Password": "123456",
5+
"Repositories": [
6+
"user1-repo0.git",
7+
"user1-repo1.git"
8+
]
9+
},
10+
{
11+
"Username": "user2",
12+
"Password": "abcdef",
13+
"Repositories": [
14+
"user2-repo0.git"
15+
]
16+
}
17+
]

main.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ import (
99
)
1010

1111
func init() {
12-
flag.BoolVar(&server.DefaultConfig.RequireAuth, "require_auth", server.DefaultConfig.RequireAuth, "enable basic auth")
13-
flag.StringVar(&server.DefaultConfig.AuthPassEnvVar, "auth_pass_env_var", server.DefaultConfig.AuthPassEnvVar, "set an env var to provide the basic auth pass as")
14-
flag.StringVar(&server.DefaultConfig.AuthUserEnvVar, "auth_user_env_var", server.DefaultConfig.AuthUserEnvVar, "set an env var to provide the basic auth user as")
12+
flag.StringVar(&server.DefaultConfig.AuthInfoFilePath, "auth_data", server.DefaultConfig.AuthInfoFilePath, "set auth info data path")
1513
flag.StringVar(&server.DefaultConfig.DefaultEnv, "default_env", server.DefaultConfig.DefaultEnv, "set the default env")
1614
flag.StringVar(&server.DefaultConfig.ProjectRoot, "project_root", server.DefaultConfig.ProjectRoot, "set project root")
1715
flag.StringVar(&server.DefaultConfig.GitBinPath, "git_bin_path", server.DefaultConfig.GitBinPath, "set git bin path")

server/server.go

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
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+
1926
type Service struct {
2027
Method string
2128
Handler func(HandlerReq)
2229
Rpc string
2330
}
2431

2532
type Config struct {
26-
RequireAuth bool
27-
AuthPassEnvVar string
28-
AuthUserEnvVar string
33+
AuthInfoFilePath string
2934
DefaultEnv string
3035
ProjectRoot string
3136
GitBinPath string
@@ -47,9 +52,7 @@ var (
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+
247297
func getInfoPacks(hr HandlerReq) {
248298
hdrCacheForever(hr.w)
249299
sendFile("text/plain; charset=utf-8", hr)

0 commit comments

Comments
 (0)