aboutsummaryrefslogtreecommitdiff
path: root/idp/idpmiddleware
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2019-01-13 05:58:25 -0800
committerChristine Dodrill <me@christine.website>2019-01-13 05:58:25 -0800
commit80cb50720bf69144f7455e3e86c230998e6707e1 (patch)
treee471748483e9e58e8d0b2c261b722d8983f708f2 /idp/idpmiddleware
parentec9d9c84c736fbf882a50fa7d9ff489206983384 (diff)
downloadx-80cb50720bf69144f7455e3e86c230998e6707e1.tar.xz
x-80cb50720bf69144f7455e3e86c230998e6707e1.zip
idp/idpmiddleware: use md5 verification
Diffstat (limited to 'idp/idpmiddleware')
-rw-r--r--idp/idpmiddleware/middleware.go90
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)
})
}