move cookies to session + config.

This commit is contained in:
Miroslav Šedivý 2021-03-17 14:09:10 +01:00
parent d06a5a2ac7
commit 4abe0a5dba
4 changed files with 66 additions and 34 deletions

View File

@ -2,17 +2,12 @@ package api
import ( import (
"net/http" "net/http"
"os"
"time"
"demodesk/neko/internal/http/auth" "demodesk/neko/internal/http/auth"
"demodesk/neko/internal/types" "demodesk/neko/internal/types"
"demodesk/neko/internal/utils" "demodesk/neko/internal/utils"
) )
var CookieExpirationDate = time.Now().Add(365 * 24 * time.Hour)
var UnsecureCookies = os.Getenv("DISABLE_SECURE_COOKIES") == "true"
type SessionLoginPayload struct { type SessionLoginPayload struct {
Username string `json:"username"` Username string `json:"username"`
Password string `json:"password"` Password string `json:"password"`
@ -36,19 +31,7 @@ func (api *ApiManagerCtx) Login(w http.ResponseWriter, r *http.Request) {
return return
} }
sameSite := http.SameSiteNoneMode api.sessions.CookieSetToken(w, token)
if UnsecureCookies {
sameSite = http.SameSiteDefaultMode
}
http.SetCookie(w, &http.Cookie{
Name: "NEKO_SESSION",
Value: token,
Expires: CookieExpirationDate,
Secure: !UnsecureCookies,
SameSite: sameSite,
HttpOnly: true,
})
utils.HttpSuccess(w, SessionDataPayload{ utils.HttpSuccess(w, SessionDataPayload{
ID: session.ID(), ID: session.ID(),
@ -66,19 +49,7 @@ func (api *ApiManagerCtx) Logout(w http.ResponseWriter, r *http.Request) {
return return
} }
sameSite := http.SameSiteNoneMode api.sessions.CookieClearToken(w)
if UnsecureCookies {
sameSite = http.SameSiteDefaultMode
}
http.SetCookie(w, &http.Cookie{
Name: "NEKO_SESSION",
Value: "",
Expires: time.Unix(0, 0),
Secure: !UnsecureCookies,
SameSite: sameSite,
HttpOnly: true,
})
utils.HttpSuccess(w, true) utils.HttpSuccess(w, true)
} }

View File

@ -1,6 +1,8 @@
package config package config
import ( import (
"time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@ -8,6 +10,10 @@ import (
type Session struct { type Session struct {
ImplicitHosting bool ImplicitHosting bool
APIToken string APIToken string
CookieName string
CookieExpiration time.Time
CookieSecure bool
} }
func (Session) Init(cmd *cobra.Command) error { func (Session) Init(cmd *cobra.Command) error {
@ -21,10 +27,30 @@ func (Session) Init(cmd *cobra.Command) error {
return err return err
} }
// cookie
cmd.PersistentFlags().String("session.cookie.name", "NEKO_SESSION", "name of the cookie that holds token")
if err := viper.BindPFlag("session.cookie.name", cmd.PersistentFlags().Lookup("session.cookie.name")); err != nil {
return err
}
cmd.PersistentFlags().Int("session.cookie.expiration", 365*24, "expiration of the cookie in hours")
if err := viper.BindPFlag("session.cookie.expiration", cmd.PersistentFlags().Lookup("session.cookie.expiration")); err != nil {
return err
}
cmd.PersistentFlags().Bool("session.cookie.secure", true, "use secure cookies")
if err := viper.BindPFlag("session.cookie.secure", cmd.PersistentFlags().Lookup("session.cookie.secure")); err != nil {
return err
}
return nil return nil
} }
func (s *Session) Set() { func (s *Session) Set() {
s.ImplicitHosting = viper.GetBool("session.implicit_hosting") s.ImplicitHosting = viper.GetBool("session.implicit_hosting")
s.APIToken = viper.GetString("session.api_token") s.APIToken = viper.GetString("session.api_token")
s.CookieName = viper.GetString("session.cookie.name")
s.CookieExpiration = time.Now().Add(time.Duration(viper.GetInt("session.cookie.expiration")) * time.Hour)
s.CookieSecure = viper.GetBool("session.cookie.secure")
} }

View File

@ -4,12 +4,45 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
"time"
"demodesk/neko/internal/types" "demodesk/neko/internal/types"
) )
func (manager *SessionManagerCtx) CookieSetToken(w http.ResponseWriter, token string) {
sameSite := http.SameSiteDefaultMode
if manager.config.CookieSecure {
sameSite = http.SameSiteNoneMode
}
http.SetCookie(w, &http.Cookie{
Name: manager.config.CookieName,
Value: token,
Expires: manager.config.CookieExpiration,
Secure: manager.config.CookieSecure,
SameSite: sameSite,
HttpOnly: true,
})
}
func (manager *SessionManagerCtx) CookieClearToken(w http.ResponseWriter) {
sameSite := http.SameSiteDefaultMode
if manager.config.CookieSecure {
sameSite = http.SameSiteNoneMode
}
http.SetCookie(w, &http.Cookie{
Name: manager.config.CookieName,
Value: "",
Expires: time.Unix(0, 0),
Secure: manager.config.CookieSecure,
SameSite: sameSite,
HttpOnly: true,
})
}
func (manager *SessionManagerCtx) Authenticate(r *http.Request) (types.Session, error) { func (manager *SessionManagerCtx) Authenticate(r *http.Request) (types.Session, error) {
token, ok := getToken(r) token, ok := manager.getToken(r)
if !ok { if !ok {
return nil, fmt.Errorf("no authentication provided") return nil, fmt.Errorf("no authentication provided")
} }
@ -26,7 +59,7 @@ func (manager *SessionManagerCtx) Authenticate(r *http.Request) (types.Session,
return session, nil return session, nil
} }
func getToken(r *http.Request) (string, bool) { func (manager *SessionManagerCtx) getToken(r *http.Request) (string, bool) {
// get from Header // get from Header
reqToken := r.Header.Get("Authorization") reqToken := r.Header.Get("Authorization")
splitToken := strings.Split(reqToken, "Bearer ") splitToken := strings.Split(reqToken, "Bearer ")
@ -35,7 +68,7 @@ func getToken(r *http.Request) (string, bool) {
} }
// get from Cookie // get from Cookie
cookie, err := r.Cookie("NEKO_SESSION") cookie, err := r.Cookie(manager.config.CookieName)
if err == nil { if err == nil {
return cookie.Value, true return cookie.Value, true
} }

View File

@ -50,5 +50,7 @@ type SessionManager interface {
ImplicitHosting() bool ImplicitHosting() bool
CookieSetToken(w http.ResponseWriter, token string)
CookieClearToken(w http.ResponseWriter)
Authenticate(r *http.Request) (Session, error) Authenticate(r *http.Request) (Session, error)
} }