all repos — quartzgun @ 92f0f035a9a89bf0b770e815607ef913a934778d

lightweight web framework in go

use TTL with LastSeen instead of hard expiry time
Iris Lightshard nilix@nilfm.cc
PGP Signature
-----BEGIN PGP SIGNATURE-----

iQIzBAABCAAdFiEEkFh6dA+k/6CXFXU4O3+8IhROY5gFAmLp4YoACgkQO3+8IhRO
Y5j8Og/+J3dzRnNx7lOJDl9+7zyez7O1aAbhoW9I+hYMt9l/ekndXFxOOeOJ4N0V
iudphPtjfpjJalHK6v/6lTHpTvv7iH4XQfeA93DtP+MHAb9LryuFYOyLPumWs3Lz
K3sQ7w1ugc14KGVLk/okb78Kclr6Mokk0QdJkYEzPG5XyjDVQ8YbML0Umz0ICNIx
JEHG+PwKeFG6XIMQXsNxBf/XtMkdYoP1O98ggQjPR7fqbsmwQCGzhfzKK9ZyFpPL
lhFiCd+Np6nsEcxMMkWb/Ye8+zOgYQ4kRMkq5EOVpQBfLxeMrw7+pNXo4WFi8GCk
6IkSW6WAg8RyFx4o58HqjdcKEvHS0aW13/xbdkspwSQ6XJtVx+XJ3JPo9f7f2EIH
ipz+dMLjA7FPavnc7yAuCNeUc5PXVQwFXcDMvoMVPL0Z+B+XPcDa2cbmENx1Gq+n
GuPs3jUnNtjwQ+l04yYziCIGLCz8ZujU69fRBjp88nUMobp1GANXwUtEBg+MRepx
yUFwedyzS75y14htvdkpTD4QLMpzqciAzB0EGqXTA5Ad+Fr+27KhFToisU8j3MFB
ocknfuLBd+1Jp6KL6lZ7JZOwwnylGF19znEi8F9pIhuy4zQ5851lSqwJzlFGn97M
u6DVeeL+L+VkvhXcDCrg/FoNfpwkvucvlWEvS/Jvo9FaJ5DhFWo=
=r875
-----END PGP SIGNATURE-----
commit

92f0f035a9a89bf0b770e815607ef913a934778d

parent

48dbb967f38ea4af6692e38c1676057315e06b2b

M auth/auth.goauth/auth.go

@@ -17,7 +17,7 @@ Data map[string]interface{}

} type UserStore interface { - InitiateSession(user string, password string) (string, error) + InitiateSession(user string, password string, ttl int) (string, error) ValidateUser(user string, sessionId string) (bool, error) EndSession(user string) error AddUser(user string, password string) error

@@ -27,13 +27,13 @@ GetLastLoginTime(user string) (time.Time, error)

GetLastTimeSeen(user string) (time.Time, error) SetData(user string, key string, value interface{}) error GetData(user string, key string) (interface{}, error) - GrantToken(user, password, scope string, minutes int) (string, error) + GrantToken(user, password string, ttl int) (string, error) ValidateToken(token string) (bool, error) ValidateTokenWithScopes(token string, scopes map[string]string) (bool, error) } func Login(user string, password string, userStore UserStore, w http.ResponseWriter, t int) error { - session, loginErr := userStore.InitiateSession(user, password) + session, loginErr := userStore.InitiateSession(user, password, t) if loginErr == nil { cookie.StoreToken("user", user, w, t) cookie.StoreToken("session", session, w, t)
M cookie/cookie.gocookie/cookie.go

@@ -18,11 +18,11 @@ }

return string(b) } -func StoreToken(field string, token string, w http.ResponseWriter, hrs int) { +func StoreToken(field string, token string, w http.ResponseWriter, ttl int) { cookie := http.Cookie{ Name: field, Value: token, - Expires: time.Now().Add(time.Duration(hrs) * time.Hour), + Expires: time.Now().Add(time.Duration(ttl) * time.Minute), } http.SetCookie(w, &cookie)
M indentalUserDB/indentalUserDB.goindentalUserDB/indentalUserDB.go

@@ -9,6 +9,7 @@ "nilfm.cc/git/quartzgun/auth"

"nilfm.cc/git/quartzgun/cookie" "os" "strings" + "strconv" "time" )

@@ -36,7 +37,7 @@ }

} } -func (self *IndentalUserDB) InitiateSession(user string, password string) (string, error) { +func (self *IndentalUserDB) InitiateSession(user string, password string, ttl int) (string, error) { if _, exists := self.Users[user]; !exists { return "", errors.New("User not in DB") }

@@ -47,30 +48,25 @@ sessionId := cookie.GenToken(64)

self.Users[user].Session = sessionId self.Users[user].LoginTime = time.Now() self.Users[user].LastSeen = time.Now() + self.SetData(user, "token_expiry", strconv.Itoa(ttl)) writeDB(self.Basis, self.Users) return sessionId, nil } -func (self *IndentalUserDB) GrantToken(user, password, scope string, minutes int) (string, error) { +func (self *IndentalUserDB) GrantToken(user, password string, ttl int) (string, error) { if _, exists := self.Users[user]; !exists { return "", errors.New("User not in DB") } if bcrypt.CompareHashAndPassword([]byte(self.Users[user].Pass), []byte(password)) != nil { return "", errors.New("Incorrect password") } - - s, err := self.GetData(user, "scope") - if err == nil && s == scope { - sessionId := cookie.GenToken(64) - self.Users[user].Session = sessionId - self.Users[user].LoginTime = time.Now() - self.Users[user].LastSeen = time.Now() - self.SetData(user, "token_expiry", time.Now().Add(time.Minute*time.Duration(minutes)).Format(timeFmt)) - writeDB(self.Basis, self.Users) - return base64.StdEncoding.EncodeToString([]byte(user + "\n" + sessionId)), nil - } - - return "", errors.New("Incorrect scope for this user") + sessionId := cookie.GenToken(64) + self.Users[user].Session = sessionId + self.Users[user].LoginTime = time.Now() + self.Users[user].LastSeen = time.Now() + self.SetData(user, "token_expiry", strconv.Itoa(ttl)) + writeDB(self.Basis, self.Users) + return base64.StdEncoding.EncodeToString([]byte(user + "\n" + sessionId)), nil } func (self *IndentalUserDB) ValidateUser(user string, sessionId string) (bool, error) {

@@ -79,10 +75,18 @@ return false, errors.New("User not in DB")

} validated := self.Users[user].Session == sessionId + expiry, err3 := self.GetData(user, "token_expiry") + expiryInt, err4 := strconv.ParseInt(expiry.(string), 10, 64) + expiryTime := self.Users[user].LastSeen.Add(time.Minute * time.Duration(expiryInt)) if validated { + if err3 == nil && err4 == nil && time.Now().After(expiryTime) { + self.EndSession(user) + return true, errors.New("Cookie or token expired") + } else { self.Users[user].LastSeen = time.Now() writeDB(self.Basis, self.Users) } + } return validated, nil }

@@ -92,14 +96,7 @@ data, err := base64.StdEncoding.DecodeString(token)

if err == nil { parts := strings.Split(string(data), "\n") if len(parts) == 2 { - expiry, err3 := self.GetData(parts[0], "token_expiry") - expiryTime, err4 := time.Parse(timeFmt, expiry.(string)) - if err3 == nil && err4 == nil && time.Now().After(expiryTime) { - self.EndSession(parts[0]) - return false, errors.New("token has expired") - } else { - return self.ValidateUser(parts[0], parts[1]) - } + return self.ValidateUser(parts[0], parts[1]) } } return false, errors.New("Token was not in a valid format: b64(USER\nSESSION)")

@@ -212,7 +209,7 @@ return nil, errors.New("User not in DB")

} data, exists := self.Users[user].Data[key] if !exists { - return nil, errors.New("No data key for user") + return nil, errors.New("Key not found in user data") } return data, nil
M middleware/middleware.gomiddleware/middleware.go

@@ -29,6 +29,8 @@ fmt.Printf("authorized user: %s\n", user)

req.Method = method next.ServeHTTP(w, req) return + } else if err != nil && err.Error() == "Cookie or token expired"{ + auth.Logout(user, userStore, w) } } }

@@ -60,14 +62,14 @@

return http.HandlerFunc(handlerFunc) } -func Authorize(next string, userStore auth.UserStore, denied string) http.Handler { +func Authorize(next string, userStore auth.UserStore, denied string, ttl int) http.Handler { handlerFunc := func(w http.ResponseWriter, req *http.Request) { err := auth.Login( req.FormValue("user"), req.FormValue("password"), userStore, w, - 24*7*52) + ttl) if err == nil { req.Method = http.MethodGet fmt.Printf("logged in as %s\n", req.FormValue("user"))

@@ -82,17 +84,16 @@

return http.HandlerFunc(handlerFunc) } -func Provision(userStore auth.UserStore, minutes int) http.Handler { +func Provision(userStore auth.UserStore, ttl int) http.Handler { handlerFunc := func(w http.ResponseWriter, req *http.Request) { user, password, ok := req.BasicAuth() - scope := req.FormValue("scope") - if ok && scope != "" { - token, err := userStore.GrantToken(user, password, scope, minutes) + if ok { + token, err := userStore.GrantToken(user, password, ttl) if err == nil { token := TokenPayload{ access_token: token, token_type: "bearer", - expires_in: minutes, + expires_in: ttl, } util.AddContextValue(req, "token", token) renderer.JSON("token").ServeHTTP(w, req)
M quartzgun_test.goquartzgun_test.go

@@ -34,7 +34,7 @@

func TestMain(m *testing.M) { udb := indentalUserDB.CreateIndentalUserDB("testData/userDB.ndtl") udb.AddUser("nilix", "questing") - sesh, _ := udb.InitiateSession("nilix", "questing") + sesh, _ := udb.InitiateSession("nilix", "questing", 60) fmt.Printf("%s // %s\n", sesh, sesh) rtr := &router.Router{

@@ -47,7 +47,7 @@

rtr.Get("/login", renderer.Template( "testData/templates/login.html")) - rtr.Post("/login", middleware.Authorize("/", udb, "/login?tryagain=1")) + rtr.Post("/login", middleware.Authorize("/", udb, "/login?tryagain=1", 120)) rtr.Get("/", middleware.Protected( renderer.Template(