diff options
| author | Max Resnick <max@ofmax.li> | 2022-11-24 08:42:46 -0800 |
|---|---|---|
| committer | Max Resnick <max@ofmax.li> | 2022-11-24 08:42:46 -0800 |
| commit | 6b9ed49ecbffa904fa0d7b281579c2472262731b (patch) | |
| tree | a4a1137754bf824f5b125fb3560dfb606f837656 /cmd | |
| parent | 3c5c26e784fda35087059bda4363ba5fca999d0d (diff) | |
| download | go-git-server-6b9ed49ecbffa904fa0d7b281579c2472262731b.tar.gz | |
relocation of code
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/main.go | 138 |
1 files changed, 11 insertions, 127 deletions
diff --git a/cmd/main.go b/cmd/main.go index 3f5cedf..962eaa1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,20 +1,15 @@ package main import ( - "context" - "crypto/rand" - "encoding/base64" - "encoding/csv" "flag" "fmt" "log" - "math/big" "net/http" - "net/http/cgi" - "os" "github.com/casbin/casbin/v2" - "golang.org/x/crypto/bcrypt" + + "git.ofmax.li/go-git-server/internal/authz" + "git.ofmax.li/go-git-server/internal/git" ) var ( @@ -24,141 +19,30 @@ var ( newToken = flag.Bool("t", false, "make a new token") ) -// LoadTokens load tokens from a csv into a map -func LoadTokens() (map[string]string, error) { - tokenMap := make(map[string]string) +func main() { // TODO this should be configurable - contents, err := os.Open("tokens.csv") - if err != nil { - fmt.Println("File reading error", err) - return tokenMap, err - } - defer contents.Close() - r := csv.NewReader(contents) - tokens, err := r.ReadAll() - if err != nil { - fmt.Println("File reading error", err) - return tokenMap, err - } - for _, acctToken := range tokens { - acct, hash := acctToken[0], acctToken[1] - tokenMap[acct] = hash - } - return tokenMap, err -} - -// NewToken generate a new token -func NewToken() (string, string, error) { - tokenBytes := make([]byte, 28) - for i := range tokenBytes { - max := big.NewInt(int64(255)) - randInt, err := rand.Int(rand.Reader, max) - if err != nil { - return "", "", err - } - tokenBytes[i] = uint8(randInt.Int64()) - } - hashBytes, err := bcrypt.GenerateFromPassword(tokenBytes, bcrypt.DefaultCost) + enf, err := casbin.NewEnforcer("./auth_model.ini", "./policy.csv") if err != nil { - return "", "", err + log.Fatalf("Couldn't load the enforcer encountered the following error: %s", err) } - token := base64.URLEncoding.EncodeToString(tokenBytes) - hash := string(hashBytes) - return token, hash, nil -} - -// GitHttpBackendHandler a handler for git cgi -func GitHttpBackendHandler(reposDir, backendCommand string) http.Handler { - projectDirEnv := fmt.Sprintf("GIT_PROJECT_ROOT=%v", reposDir) - return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - ctx := req.Context() - uid := ctx.Value("urn") - git := &cgi.Handler{ - Path: "/bin/sh", - Args: []string{"-c", backendCommand}, - Dir: ".", - Env: []string{ - projectDirEnv, - "GIT_HTTP_EXPORT_ALL=1", - fmt.Sprintf("REMOTE_USER=%s", uid), - }, - } - git.ServeHTTP(rw, req) - }) -} - -// Authentication middleware to enforce authentication of all requests. -func Authentication(authMap map[string]string, next http.Handler) http.Handler { - return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - u, p, ok := req.BasicAuth() - if !ok { - rw.Header().Set("WWW-Authenticate", `Basic realm="git"`) - http.Error(rw, "Authentication Required", 401) - return - } - urn := fmt.Sprintf("uid:%s", u) - hash, ok := authMap[urn] - if !ok { - http.Error(rw, "Bad Request", 400) - return - } - token, err := base64.URLEncoding.DecodeString(p) - if err != nil { - http.Error(rw, "Bad Request", 400) - return - } - if err := bcrypt.CompareHashAndPassword([]byte(hash), token); err != nil { - http.Error(rw, "Bad Request", 400) - return - } - ctx := context.WithValue(req.Context(), "urn", urn) - next.ServeHTTP(rw, req.WithContext(ctx)) - }) -} - -func Authorization(enf *casbin.Enforcer, next http.Handler) http.Handler { - return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - ctx := req.Context() - urn := ctx.Value("urn") - repo := req.URL.Path - action := req.Method - // defer req.Body.Close() - // body, _ := io.ReadAll(req.Body) - // log.Printf("%s", body) - ok, err := enf.Enforce(urn, repo, action) - if err != nil { - log.Printf("error running enforce %s", err) - http.Error(rw, "Bad Request", http.StatusBadRequest) - } - if !ok { - log.Printf("Access denied") - http.Error(rw, "Access denied", http.StatusUnauthorized) - } - log.Printf("Method %s Url %s", action, repo) - next.ServeHTTP(rw, req.WithContext(ctx)) - }) -} - -func main() { - // TODO this should be configurable - enf, _ := casbin.NewEnforcer("./auth_model.ini", "./policy.csv") flag.Parse() if *newToken { - token, hash, err := NewToken() + token, hash, err := authz.GenerateNewToken() if err != nil { log.Fatal(err) } fmt.Printf("token: %s\nhash: %s\n", token, hash) return } - tokens, err := LoadTokens() + tokens := authz.NewTokenMap() + err = tokens.LoadTokensFromFile("./tokens.csv") if err != nil { log.Fatal(err) } router := http.NewServeMux() // TODO we don't want to use a global // de-reference args - router.Handle("/", GitHttpBackendHandler(*reposDir, *backendCommand)) - mux := Authentication(tokens, Authorization(enf, router)) + router.Handle("/", git.GitHttpBackendHandler(*reposDir, *backendCommand)) + mux := authz.Authentication(tokens, authz.Authorization(enf, router)) log.Fatal(http.ListenAndServe(":8080", mux)) } |