diff options
| author | Christine Dodrill <me@christine.website> | 2019-01-13 05:58:25 -0800 |
|---|---|---|
| committer | Christine Dodrill <me@christine.website> | 2019-01-13 05:58:25 -0800 |
| commit | 80cb50720bf69144f7455e3e86c230998e6707e1 (patch) | |
| tree | e471748483e9e58e8d0b2c261b722d8983f708f2 /idp/idpmiddleware | |
| parent | ec9d9c84c736fbf882a50fa7d9ff489206983384 (diff) | |
| download | x-80cb50720bf69144f7455e3e86c230998e6707e1.tar.xz x-80cb50720bf69144f7455e3e86c230998e6707e1.zip | |
idp/idpmiddleware: use md5 verification
Diffstat (limited to 'idp/idpmiddleware')
| -rw-r--r-- | idp/idpmiddleware/middleware.go | 90 |
1 files changed, 79 insertions, 11 deletions
diff --git a/idp/idpmiddleware/middleware.go b/idp/idpmiddleware/middleware.go index b7a961b..b7e7388 100644 --- a/idp/idpmiddleware/middleware.go +++ b/idp/idpmiddleware/middleware.go @@ -1,17 +1,69 @@ package idpmiddleware import ( + "context" + "crypto/md5" + "encoding/json" + "errors" + "fmt" "net/http" "net/url" "sync" "time" - "github.com/kr/pretty" "github.com/pborman/uuid" "within.website/ln" "within.website/ln/opname" ) +// hash is a simple wrapper around the MD5 algorithm implementation in the +// Go standard library. It takes in data and a salt and returns the hashed +// representation. +func hash(data string, salt string) string { + output := md5.Sum([]byte(data + salt)) + return fmt.Sprintf("%x", output) +} + +func verify(ctx context.Context, idpServer, state, code string) *http.Request { + u, err := url.Parse(idpServer) + if err != nil { + panic(err) + } + + u.Path = "/auth" + q := u.Query() + q.Set("code", code) + q.Set("state", state) + u.RawQuery = q.Encode() + + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + if err != nil { + panic(err) + } + + req.Header.Set("Accept", "application/json") + req = req.WithContext(ctx) + + return req +} + +func validate(resp *http.Response) (string, error) { + result := struct { + Me string `json:"me"` + }{} + + if resp.StatusCode != 200 { + return "", fmt.Errorf("wanted status 200, got: %d", resp.StatusCode) + } + + err := json.NewDecoder(resp.Body).Decode(&result) + if err != nil { + return "", err + } + + return result.Me, nil +} + // Protect protects a given URL behind your given idp(1) server. func Protect(idpServer, me, selfURL string) func(next http.Handler) http.Handler { lock := sync.Mutex{} @@ -26,26 +78,47 @@ func Protect(idpServer, me, selfURL string) func(next http.Handler) http.Handler ctx = ln.WithF(ctx, ln.F{"as": me, "state": v.Get("state"), "code": v.Get("code")}) ln.Log(ctx, ln.Info("login")) lock.Lock() - pretty.Println(codes) + defer lock.Unlock() if cd := v.Get("state"); codes[cd] == cd { + ctx = opname.With(ctx, "verify") + resp, err := http.DefaultClient.Do(verify(ctx, idpServer, v.Get("state"), v.Get("code"))) + if err != nil { + ln.Error(ctx, err) + http.Error(w, "nope", http.StatusInternalServerError) + return + } + + got, err := validate(resp) + if err != nil { + ln.Error(ctx, err) + http.Error(w, "not valid", http.StatusInternalServerError) + return + } + + if me != got { + ln.Error(ctx, errors.New("hacking attempt")) + http.Error(w, "...", http.StatusNotAcceptable) + return + } + ln.Log(ctx, ln.Info("setting cookie")) http.SetCookie(w, &http.Cookie{ Name: "auth", - Value: me, + Value: hash(me, idpServer), HttpOnly: true, Expires: time.Now().Add(900 * time.Hour), Path: "/", SameSite: http.SameSiteLaxMode, }) + delete(codes, cd) - http.Error(w, "success", http.StatusOK) + http.Redirect(w, r, selfURL, http.StatusPermanentRedirect) } - lock.Unlock() return } cookie, err := r.Cookie("auth") - if err != nil { + if err != nil || cookie.Value != hash(me, idpServer) { u, err := url.Parse(idpServer) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -70,11 +143,6 @@ func Protect(idpServer, me, selfURL string) func(next http.Handler) http.Handler return } - if cookie.Value != me { - http.Error(w, "wrong identity", http.StatusBadRequest) - return - } - next.ServeHTTP(w, r) }) } |
