aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerek Stevens <nilix@nilfm.cc>2022-08-02 20:46:34 -0600
committerDerek Stevens <nilix@nilfm.cc>2022-08-02 20:46:34 -0600
commit92f0f035a9a89bf0b770e815607ef913a934778d (patch)
tree3a7ebdb1bf705a1bf2a2f35b2e2ec3ad3026de76
parent48dbb967f38ea4af6692e38c1676057315e06b2b (diff)
use TTL with LastSeen instead of hard expiry time
-rw-r--r--auth/auth.go6
-rw-r--r--cookie/cookie.go4
-rw-r--r--indentalUserDB/indentalUserDB.go45
-rw-r--r--middleware/middleware.go15
-rw-r--r--quartzgun_test.go4
5 files changed, 36 insertions, 38 deletions
diff --git a/auth/auth.go b/auth/auth.go
index 6b79b04..8466d32 100644
--- a/auth/auth.go
+++ b/auth/auth.go
@@ -17,7 +17,7 @@ type User struct {
}
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 @@ type UserStore interface {
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)
diff --git a/cookie/cookie.go b/cookie/cookie.go
index eda305c..ff78b0a 100644
--- a/cookie/cookie.go
+++ b/cookie/cookie.go
@@ -18,11 +18,11 @@ func GenToken(length int) string {
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)
diff --git a/indentalUserDB/indentalUserDB.go b/indentalUserDB/indentalUserDB.go
index fda255d..8c8bcf8 100644
--- a/indentalUserDB/indentalUserDB.go
+++ b/indentalUserDB/indentalUserDB.go
@@ -9,6 +9,7 @@ import (
"nilfm.cc/git/quartzgun/cookie"
"os"
"strings"
+ "strconv"
"time"
)
@@ -36,7 +37,7 @@ func CreateIndentalUserDB(filePath string) *IndentalUserDB {
}
}
-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 @@ func (self *IndentalUserDB) InitiateSession(user string, password string) (strin
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 @@ func (self *IndentalUserDB) ValidateUser(user string, sessionId string) (bool, e
}
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 @@ func (self *IndentalUserDB) ValidateToken(token string) (bool, error) {
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 @@ func (self *IndentalUserDB) GetData(user string, key string) (interface{}, error
}
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
diff --git a/middleware/middleware.go b/middleware/middleware.go
index 67b38a1..046f5c9 100644
--- a/middleware/middleware.go
+++ b/middleware/middleware.go
@@ -29,6 +29,8 @@ func Protected(next http.Handler, method string, userStore auth.UserStore, login
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 @@ func Bunt(next string, userStore auth.UserStore, denied string) http.Handler {
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 @@ func Authorize(next string, userStore auth.UserStore, denied string) http.Handle
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)
diff --git a/quartzgun_test.go b/quartzgun_test.go
index cc99b83..ca7b2be 100644
--- a/quartzgun_test.go
+++ b/quartzgun_test.go
@@ -34,7 +34,7 @@ func ApiSomething(next http.Handler) http.Handler {
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 @@ func TestMain(m *testing.M) {
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(