aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorMax Resnick <max@ofmax.li>2022-11-24 08:42:46 -0800
committerMax Resnick <max@ofmax.li>2022-11-24 08:42:46 -0800
commit6b9ed49ecbffa904fa0d7b281579c2472262731b (patch)
treea4a1137754bf824f5b125fb3560dfb606f837656 /cmd
parent3c5c26e784fda35087059bda4363ba5fca999d0d (diff)
downloadgo-git-server-6b9ed49ecbffa904fa0d7b281579c2472262731b.tar.gz
relocation of code
Diffstat (limited to 'cmd')
-rw-r--r--cmd/main.go138
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))
}