feat: allow access token expiration to be set in the config

This commit is contained in:
Jordan Knott 2020-12-30 21:10:34 -06:00
parent f16cceb0e1
commit a8b3809515
6 changed files with 35 additions and 12 deletions

View File

@ -52,12 +52,12 @@ func (r *ErrMalformedToken) Error() string {
} }
// NewAccessToken generates a new JWT access token with the correct claims // NewAccessToken generates a new JWT access token with the correct claims
func NewAccessToken(userID string, restrictedMode RestrictedMode, orgRole string, jwtKey []byte) (string, error) { func NewAccessToken(userID string, restrictedMode RestrictedMode, orgRole string, jwtKey []byte, expirationTime time.Duration) (string, error) {
role := RoleMember role := RoleMember
if orgRole == "admin" { if orgRole == "admin" {
role = RoleAdmin role = RoleAdmin
} }
accessExpirationTime := time.Now().Add(5 * time.Second) accessExpirationTime := time.Now().Add(expirationTime)
accessClaims := &AccessTokenClaims{ accessClaims := &AccessTokenClaims{
UserID: userID, UserID: userID,
Restricted: restrictedMode, Restricted: restrictedMode,

View File

@ -80,6 +80,7 @@ func Execute() {
viper.SetDefault("database.user", "taskcafe") viper.SetDefault("database.user", "taskcafe")
viper.SetDefault("database.password", "taskcafe_test") viper.SetDefault("database.password", "taskcafe_test")
viper.SetDefault("database.port", "5432") viper.SetDefault("database.port", "5432")
viper.SetDefault("security.token_expiration", "15m")
viper.SetDefault("queue.broker", "amqp://guest:guest@localhost:5672/") viper.SetDefault("queue.broker", "amqp://guest:guest@localhost:5672/")
viper.SetDefault("queue.store", "memcache://localhost:11211") viper.SetDefault("queue.store", "memcache://localhost:11211")

View File

@ -76,6 +76,7 @@ func newWebCmd() *cobra.Command {
log.Warn("server.secret is not set, generating a random secret") log.Warn("server.secret is not set, generating a random secret")
secret = uuid.New().String() secret = uuid.New().String()
} }
security, err := utils.GetSecurityConfig(viper.GetString("security.token_expiration"), []byte(secret))
r, _ := route.NewRouter(db, utils.EmailConfig{ r, _ := route.NewRouter(db, utils.EmailConfig{
From: viper.GetString("smtp.from"), From: viper.GetString("smtp.from"),
Host: viper.GetString("smtp.host"), Host: viper.GetString("smtp.host"),
@ -83,7 +84,7 @@ func newWebCmd() *cobra.Command {
Username: viper.GetString("smtp.username"), Username: viper.GetString("smtp.username"),
Password: viper.GetString("smtp.password"), Password: viper.GetString("smtp.password"),
InsecureSkipVerify: viper.GetBool("smtp.skip_verify"), InsecureSkipVerify: viper.GetBool("smtp.skip_verify"),
}, []byte(secret)) }, security)
return http.ListenAndServe(viper.GetString("server.hostname"), r) return http.ListenAndServe(viper.GetString("server.hostname"), r)
}, },
} }

View File

@ -143,7 +143,7 @@ func (h *TaskcafeHandler) RefreshTokenHandler(w http.ResponseWriter, r *http.Req
} }
log.Info("here 1") log.Info("here 1")
accessTokenString, err := auth.NewAccessToken(token.UserID.String(), auth.Unrestricted, user.RoleCode, h.jwtKey) accessTokenString, err := auth.NewAccessToken(token.UserID.String(), auth.Unrestricted, user.RoleCode, h.SecurityConfig.Secret, h.SecurityConfig.AccessTokenExpiration)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
@ -220,7 +220,7 @@ func (h *TaskcafeHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
refreshExpiresAt := refreshCreatedAt.AddDate(0, 0, 1) refreshExpiresAt := refreshCreatedAt.AddDate(0, 0, 1)
refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), db.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt}) refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), db.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt})
accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.jwtKey) accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.SecurityConfig.Secret, h.SecurityConfig.AccessTokenExpiration)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
} }
@ -283,7 +283,7 @@ func (h *TaskcafeHandler) InstallHandler(w http.ResponseWriter, r *http.Request)
refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), db.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt}) refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), db.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt})
log.WithField("userID", user.UserID.String()).Info("creating install access token") log.WithField("userID", user.UserID.String()).Info("creating install access token")
accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.jwtKey) accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.SecurityConfig.Secret, h.SecurityConfig.AccessTokenExpiration)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
} }
@ -386,7 +386,7 @@ func (h *TaskcafeHandler) ConfirmUser(w http.ResponseWriter, r *http.Request) {
refreshExpiresAt := refreshCreatedAt.AddDate(0, 0, 1) refreshExpiresAt := refreshCreatedAt.AddDate(0, 0, 1)
refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), db.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt}) refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), db.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt})
accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.jwtKey) accessTokenString, err := auth.NewAccessToken(user.UserID.String(), auth.Unrestricted, user.RoleCode, h.SecurityConfig.Secret, h.SecurityConfig.AccessTokenExpiration)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
} }

View File

@ -61,11 +61,11 @@ func (h FrontendHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// TaskcafeHandler contains all the route handlers // TaskcafeHandler contains all the route handlers
type TaskcafeHandler struct { type TaskcafeHandler struct {
repo db.Repository repo db.Repository
jwtKey []byte SecurityConfig utils.SecurityConfig
} }
// NewRouter creates a new router for chi // NewRouter creates a new router for chi
func NewRouter(dbConnection *sqlx.DB, emailConfig utils.EmailConfig, jwtKey []byte) (chi.Router, error) { func NewRouter(dbConnection *sqlx.DB, emailConfig utils.EmailConfig, securityConfig utils.SecurityConfig) (chi.Router, error) {
formatter := new(log.TextFormatter) formatter := new(log.TextFormatter)
formatter.TimestampFormat = "02-01-2006 15:04:05" formatter.TimestampFormat = "02-01-2006 15:04:05"
formatter.FullTimestamp = true formatter.FullTimestamp = true
@ -81,7 +81,7 @@ func NewRouter(dbConnection *sqlx.DB, emailConfig utils.EmailConfig, jwtKey []by
r.Use(middleware.Timeout(60 * time.Second)) r.Use(middleware.Timeout(60 * time.Second))
repository := db.NewRepository(dbConnection) repository := db.NewRepository(dbConnection)
taskcafeHandler := TaskcafeHandler{*repository, jwtKey} taskcafeHandler := TaskcafeHandler{*repository, securityConfig}
var imgServer = http.FileServer(http.Dir("./uploads/")) var imgServer = http.FileServer(http.Dir("./uploads/"))
r.Group(func(mux chi.Router) { r.Group(func(mux chi.Router) {
@ -91,7 +91,7 @@ func NewRouter(dbConnection *sqlx.DB, emailConfig utils.EmailConfig, jwtKey []by
mux.Post("/auth/confirm", taskcafeHandler.ConfirmUser) mux.Post("/auth/confirm", taskcafeHandler.ConfirmUser)
mux.Post("/auth/register", taskcafeHandler.RegisterUser) mux.Post("/auth/register", taskcafeHandler.RegisterUser)
}) })
auth := AuthenticationMiddleware{jwtKey} auth := AuthenticationMiddleware{securityConfig.Secret}
r.Group(func(mux chi.Router) { r.Group(func(mux chi.Router) {
mux.Use(auth.Middleware) mux.Use(auth.Middleware)
mux.Post("/users/me/avatar", taskcafeHandler.ProfileImageUpload) mux.Post("/users/me/avatar", taskcafeHandler.ProfileImageUpload)

View File

@ -0,0 +1,21 @@
package utils
import (
"time"
log "github.com/sirupsen/logrus"
)
type SecurityConfig struct {
AccessTokenExpiration time.Duration
Secret []byte
}
func GetSecurityConfig(accessTokenExp string, secret []byte) (SecurityConfig, error) {
exp, err := time.ParseDuration(accessTokenExp)
if err != nil {
log.WithError(err).Error("issue parsing duration")
return SecurityConfig{}, err
}
return SecurityConfig{AccessTokenExpiration: exp, Secret: secret}, nil
}