fix: user session access
This commit is contained in:
parent
ac49b5bb70
commit
82a2a42f84
|
@ -7,4 +7,6 @@ const (
|
||||||
TokenTypeAccessToken = "access_token"
|
TokenTypeAccessToken = "access_token"
|
||||||
// TokenTypeIdentityToken is the identity_token token type
|
// TokenTypeIdentityToken is the identity_token token type
|
||||||
TokenTypeIdentityToken = "id_token"
|
TokenTypeIdentityToken = "id_token"
|
||||||
|
// TokenTypeSessionToken is the session_token type used for browser session
|
||||||
|
TokenTypeSessionToken = "session_token"
|
||||||
)
|
)
|
||||||
|
|
|
@ -38,7 +38,6 @@ func (user *User) AsAPIUser() *model.User {
|
||||||
email := user.Email
|
email := user.Email
|
||||||
createdAt := user.CreatedAt
|
createdAt := user.CreatedAt
|
||||||
updatedAt := user.UpdatedAt
|
updatedAt := user.UpdatedAt
|
||||||
revokedTimestamp := user.RevokedTimestamp
|
|
||||||
return &model.User{
|
return &model.User{
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
|
@ -55,7 +54,7 @@ func (user *User) AsAPIUser() *model.User {
|
||||||
PhoneNumberVerified: &isPhoneVerified,
|
PhoneNumberVerified: &isPhoneVerified,
|
||||||
Picture: user.Picture,
|
Picture: user.Picture,
|
||||||
Roles: strings.Split(user.Roles, ","),
|
Roles: strings.Split(user.Roles, ","),
|
||||||
RevokedTimestamp: revokedTimestamp,
|
RevokedTimestamp: user.RevokedTimestamp,
|
||||||
CreatedAt: &createdAt,
|
CreatedAt: &createdAt,
|
||||||
UpdatedAt: &updatedAt,
|
UpdatedAt: &updatedAt,
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,6 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error)
|
||||||
func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
func (p *provider) GetUserByEmail(email string) (models.User, error) {
|
||||||
var user models.User
|
var user models.User
|
||||||
result := p.db.Where("email = ?", email).First(&user)
|
result := p.db.Where("email = ?", email).First(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return user, result.Error
|
||||||
}
|
}
|
||||||
|
@ -110,7 +109,6 @@ func (p *provider) GetUserByID(id string) (models.User, error) {
|
||||||
var user models.User
|
var user models.User
|
||||||
|
|
||||||
result := p.db.Where("id = ?", id).First(&user)
|
result := p.db.Where("id = ?", id).First(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return user, result.Error
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,10 +222,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||||
// based on the response type, generate the response
|
// based on the response type, generate the response
|
||||||
if isResponseTypeCode {
|
if isResponseTypeCode {
|
||||||
// rollover the session for security
|
// rollover the session for security
|
||||||
err = memorystore.Provider.RemoveState(sessionToken)
|
go memorystore.Provider.DeleteUserSession(user.ID, claims.Nonce)
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to remove state: ", err)
|
|
||||||
}
|
|
||||||
nonce := uuid.New().String()
|
nonce := uuid.New().String()
|
||||||
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope)
|
newSessionTokenData, newSessionToken, err := token.CreateSessionToken(user, nonce, claims.Roles, scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -246,7 +243,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.SetUserSession(user.ID, newSessionToken, newSessionTokenData.Nonce)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken)
|
||||||
cookie.SetSession(gc, newSessionToken)
|
cookie.SetSession(gc, newSessionToken)
|
||||||
code := uuid.New().String()
|
code := uuid.New().String()
|
||||||
memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken)
|
memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken)
|
||||||
|
@ -283,9 +280,9 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
memorystore.Provider.RemoveState(sessionToken)
|
go memorystore.Provider.DeleteUserSession(user.ID, claims.Nonce)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.FingerPrintHash, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.AccessToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
|
||||||
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
|
@ -308,7 +305,7 @@ func AuthorizeHandler() gin.HandlerFunc {
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res["refresh_token"] = authToken.RefreshToken.Token
|
res["refresh_token"] = authToken.RefreshToken.Token
|
||||||
params += "&refresh_token=" + authToken.RefreshToken.Token
|
params += "&refresh_token=" + authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.RefreshToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isQuery {
|
if isQuery {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -10,6 +11,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/crypto"
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler to logout user
|
// Handler to logout user
|
||||||
|
@ -35,12 +37,17 @@ func LogoutHandler() gin.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fingerPrint := string(decryptedFingerPrint)
|
var sessionData token.SessionData
|
||||||
|
err = json.Unmarshal([]byte(decryptedFingerPrint), &sessionData)
|
||||||
err = memorystore.Provider.RemoveState(fingerPrint)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to remove state: ", err)
|
log.Debug("Failed to decrypt fingerprint: ", err)
|
||||||
|
gc.JSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memorystore.Provider.DeleteUserSession(sessionData.Subject, sessionData.Nonce)
|
||||||
cookie.DeleteSession(gc)
|
cookie.DeleteSession(gc)
|
||||||
|
|
||||||
if redirectURL != "" {
|
if redirectURL != "" {
|
||||||
|
|
|
@ -36,7 +36,6 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
log.Debug("Invalid oauth state: ", state)
|
log.Debug("Invalid oauth state: ", state)
|
||||||
c.JSON(400, gin.H{"error": "invalid oauth state"})
|
c.JSON(400, gin.H{"error": "invalid oauth state"})
|
||||||
}
|
}
|
||||||
memorystore.Provider.GetState(state)
|
|
||||||
// contains random token, redirect url, role
|
// contains random token, redirect url, role
|
||||||
sessionSplit := strings.Split(state, "___")
|
sessionSplit := strings.Split(state, "___")
|
||||||
|
|
||||||
|
@ -46,6 +45,9 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove state from store
|
||||||
|
go memorystore.Provider.RemoveState(state)
|
||||||
|
|
||||||
stateValue := sessionSplit[0]
|
stateValue := sessionSplit[0]
|
||||||
redirectURL := sessionSplit[1]
|
redirectURL := sessionSplit[1]
|
||||||
inputRoles := strings.Split(sessionSplit[2], ",")
|
inputRoles := strings.Split(sessionSplit[2], ",")
|
||||||
|
@ -117,9 +119,11 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
user.EmailVerifiedAt = &now
|
user.EmailVerifiedAt = &now
|
||||||
user, _ = db.Provider.AddUser(user)
|
user, _ = db.Provider.AddUser(user)
|
||||||
} else {
|
} else {
|
||||||
|
user = existingUser
|
||||||
if user.RevokedTimestamp != nil {
|
if user.RevokedTimestamp != nil {
|
||||||
log.Debug("User access revoked at: ", user.RevokedTimestamp)
|
log.Debug("User access revoked at: ", user.RevokedTimestamp)
|
||||||
c.JSON(400, gin.H{"error": "user access has been revoked"})
|
c.JSON(400, gin.H{"error": "user access has been revoked"})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// user exists in db, check if method was google
|
// user exists in db, check if method was google
|
||||||
|
@ -128,7 +132,6 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
if !strings.Contains(signupMethod, provider) {
|
if !strings.Contains(signupMethod, provider) {
|
||||||
signupMethod = signupMethod + "," + provider
|
signupMethod = signupMethod + "," + provider
|
||||||
}
|
}
|
||||||
user = existingUser
|
|
||||||
user.SignupMethods = signupMethod
|
user.SignupMethods = signupMethod
|
||||||
|
|
||||||
if user.EmailVerifiedAt == nil {
|
if user.EmailVerifiedAt == nil {
|
||||||
|
@ -200,12 +203,12 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token
|
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token
|
||||||
|
|
||||||
cookie.SetSession(c, authToken.FingerPrintHash)
|
cookie.SetSession(c, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.FingerPrintHash, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.AccessToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
params = params + `&refresh_token=` + authToken.RefreshToken.Token
|
params = params + `&refresh_token=` + authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.RefreshToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
go db.Provider.AddSession(models.Session{
|
go db.Provider.AddSession(models.Session{
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Revoke handler to revoke refresh token
|
// Revoke handler to revoke refresh token
|
||||||
|
@ -45,7 +46,17 @@ func RevokeHandler() gin.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.RemoveState(refreshToken)
|
claims, err := token.ParseJWTToken(refreshToken)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Client ID is invalid: ", clientID)
|
||||||
|
gc.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": err.Error(),
|
||||||
|
"error_description": "Failed to parse jwt",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
memorystore.Provider.DeleteUserSession(claims["sub"].(string), claims["nonce"].(string))
|
||||||
|
|
||||||
gc.JSON(http.StatusOK, gin.H{
|
gc.JSON(http.StatusOK, gin.H{
|
||||||
"message": "Token revoked successfully",
|
"message": "Token revoked successfully",
|
||||||
|
|
|
@ -107,6 +107,7 @@ func TokenHandler() gin.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go memorystore.Provider.RemoveState(encryptedCode)
|
||||||
// split session data
|
// split session data
|
||||||
// it contains code@sessiontoken
|
// it contains code@sessiontoken
|
||||||
sessionDataSplit := strings.Split(sessionData, "@")
|
sessionDataSplit := strings.Split(sessionData, "@")
|
||||||
|
@ -130,11 +131,11 @@ func TokenHandler() gin.HandlerFunc {
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// rollover the session for security
|
|
||||||
memorystore.Provider.RemoveState(sessionDataSplit[1])
|
|
||||||
userID = claims.Subject
|
userID = claims.Subject
|
||||||
roles = claims.Roles
|
roles = claims.Roles
|
||||||
scope = claims.Scope
|
scope = claims.Scope
|
||||||
|
// rollover the session for security
|
||||||
|
go memorystore.Provider.DeleteUserSession(userID, claims.Nonce)
|
||||||
} else {
|
} else {
|
||||||
// validate refresh token
|
// validate refresh token
|
||||||
if refreshToken == "" {
|
if refreshToken == "" {
|
||||||
|
@ -163,7 +164,7 @@ func TokenHandler() gin.HandlerFunc {
|
||||||
scope = append(scope, v.(string))
|
scope = append(scope, v.(string))
|
||||||
}
|
}
|
||||||
// remove older refresh token and rotate it for security
|
// remove older refresh token and rotate it for security
|
||||||
memorystore.Provider.RemoveState(refreshToken)
|
go memorystore.Provider.DeleteUserSession(userID, claims["nonce"].(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.Provider.GetUserByID(userID)
|
user, err := db.Provider.GetUserByID(userID)
|
||||||
|
@ -185,8 +186,8 @@ func TokenHandler() gin.HandlerFunc {
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.FingerPrintHash, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.AccessToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
|
||||||
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
|
@ -204,7 +205,7 @@ func TokenHandler() gin.HandlerFunc {
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res["refresh_token"] = authToken.RefreshToken.Token
|
res["refresh_token"] = authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.RefreshToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.JSON(http.StatusOK, res)
|
gc.JSON(http.StatusOK, res)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
@ -107,12 +108,12 @@ func VerifyEmailHandler() gin.HandlerFunc {
|
||||||
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token
|
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token
|
||||||
|
|
||||||
cookie.SetSession(c, authToken.FingerPrintHash)
|
cookie.SetSession(c, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.FingerPrintHash, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.AccessToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
params = params + `&refresh_token=${refresh_token}`
|
params = params + `&refresh_token=` + authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.RefreshToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirectURL == "" {
|
if redirectURL == "" {
|
||||||
|
|
|
@ -7,9 +7,9 @@ type Provider interface {
|
||||||
// GetAllUserSessions returns all the user sessions from the session store
|
// GetAllUserSessions returns all the user sessions from the session store
|
||||||
GetAllUserSessions(userId string) (map[string]string, error)
|
GetAllUserSessions(userId string) (map[string]string, error)
|
||||||
// GetUserSession returns the session token for given token
|
// GetUserSession returns the session token for given token
|
||||||
GetUserSession(userId, token string) (string, error)
|
GetUserSession(userId, key string) (string, error)
|
||||||
// DeleteUserSession deletes the user session
|
// DeleteUserSession deletes the user session
|
||||||
DeleteUserSession(userId, token string) error
|
DeleteUserSession(userId, key string) error
|
||||||
// DeleteAllSessions deletes all the sessions from the session store
|
// DeleteAllSessions deletes all the sessions from the session store
|
||||||
DeleteAllUserSessions(userId string) error
|
DeleteAllUserSessions(userId string) error
|
||||||
|
|
||||||
|
|
|
@ -37,18 +37,24 @@ func (c *provider) GetAllUserSessions(userID string) (map[string]string, error)
|
||||||
|
|
||||||
// GetUserSession returns the user session from redis store.
|
// GetUserSession returns the user session from redis store.
|
||||||
func (c *provider) GetUserSession(userId, key string) (string, error) {
|
func (c *provider) GetUserSession(userId, key string) (string, error) {
|
||||||
var res string
|
data, err := c.store.HGet(c.ctx, userId, key).Result()
|
||||||
err := c.store.HGet(c.ctx, userId, key).Scan(&res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return res, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUserSession deletes the user session from redis store.
|
// DeleteUserSession deletes the user session from redis store.
|
||||||
func (c *provider) DeleteUserSession(userId, key string) error {
|
func (c *provider) DeleteUserSession(userId, key string) error {
|
||||||
err := c.store.HDel(c.ctx, userId, key).Err()
|
if err := c.store.HDel(c.ctx, userId, constants.TokenTypeSessionToken+"_"+key).Err(); err != nil {
|
||||||
if err != nil {
|
log.Debug("Error deleting user session from redis: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.store.HDel(c.ctx, userId, constants.TokenTypeAccessToken+"_"+key).Err(); err != nil {
|
||||||
|
log.Debug("Error deleting user session from redis: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.store.HDel(c.ctx, userId, constants.TokenTypeRefreshToken+"_"+key).Err(); err != nil {
|
||||||
log.Debug("Error deleting user session from redis: ", err)
|
log.Debug("Error deleting user session from redis: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -57,7 +63,7 @@ func (c *provider) DeleteUserSession(userId, key string) error {
|
||||||
|
|
||||||
// DeleteAllUserSessions deletes all the user session from redis
|
// DeleteAllUserSessions deletes all the user session from redis
|
||||||
func (c *provider) DeleteAllUserSessions(userID string) error {
|
func (c *provider) DeleteAllUserSessions(userID string) error {
|
||||||
err := c.store.HDel(c.ctx, userID).Err()
|
err := c.store.Del(c.ctx, userID).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error deleting all user sessions from redis: ", err)
|
log.Debug("Error deleting all user sessions from redis: ", err)
|
||||||
return err
|
return err
|
||||||
|
@ -78,13 +84,13 @@ func (c *provider) SetState(key, value string) error {
|
||||||
|
|
||||||
// GetState gets the state from redis store.
|
// GetState gets the state from redis store.
|
||||||
func (c *provider) GetState(key string) (string, error) {
|
func (c *provider) GetState(key string) (string, error) {
|
||||||
var res string
|
data, err := c.store.Get(c.ctx, stateStorePrefix+key).Result()
|
||||||
err := c.store.Get(c.ctx, stateStorePrefix+key).Scan(&res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error getting token from redis store: ", err)
|
log.Debug("error getting token from redis store: ", err)
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveState removes the state from redis store.
|
// RemoveState removes the state from redis store.
|
||||||
|
@ -142,22 +148,20 @@ func (c *provider) UpdateEnvVariable(key string, value interface{}) error {
|
||||||
|
|
||||||
// GetStringStoreEnvVariable to get the string env variable from env store
|
// GetStringStoreEnvVariable to get the string env variable from env store
|
||||||
func (c *provider) GetStringStoreEnvVariable(key string) (string, error) {
|
func (c *provider) GetStringStoreEnvVariable(key string) (string, error) {
|
||||||
var res string
|
data, err := c.store.HGet(c.ctx, envStorePrefix, key).Result()
|
||||||
err := c.store.HGet(c.ctx, envStorePrefix, key).Scan(&res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBoolStoreEnvVariable to get the bool env variable from env store
|
// GetBoolStoreEnvVariable to get the bool env variable from env store
|
||||||
func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) {
|
func (c *provider) GetBoolStoreEnvVariable(key string) (bool, error) {
|
||||||
var res bool
|
data, err := c.store.HGet(c.ctx, envStorePrefix, key).Result()
|
||||||
err := c.store.HGet(c.ctx, envStorePrefix, key).Scan(res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return data == "1", nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,12 +117,12 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.FingerPrintHash, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.AccessToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res.RefreshToken = &authToken.RefreshToken.Token
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.RefreshToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
go db.Provider.AddSession(models.Session{
|
go db.Provider.AddSession(models.Session{
|
||||||
|
|
|
@ -41,7 +41,7 @@ func LogoutResolver(ctx context.Context) (*model.Response, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.DeleteUserSession(sessionData.Subject, fingerprintHash)
|
memorystore.Provider.DeleteUserSession(sessionData.Subject, sessionData.Nonce)
|
||||||
cookie.DeleteSession(gc)
|
cookie.DeleteSession(gc)
|
||||||
|
|
||||||
res := &model.Response{
|
res := &model.Response{
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
@ -29,7 +30,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
||||||
|
|
||||||
sessionToken, err := cookie.GetSession(gc)
|
sessionToken, err := cookie.GetSession(gc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get session token", err)
|
log.Debug("Failed to get session token: ", err)
|
||||||
return res, errors.New("unauthorized")
|
return res, errors.New("unauthorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,10 +77,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
// rollover the session for security
|
// rollover the session for security
|
||||||
memorystore.Provider.RemoveState(sessionToken)
|
go memorystore.Provider.DeleteUserSession(userID, claims.Nonce)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.FingerPrintHash, authToken.FingerPrint)
|
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.AccessToken.Token, authToken.FingerPrint)
|
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
|
||||||
|
|
||||||
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
if expiresIn <= 0 {
|
if expiresIn <= 0 {
|
||||||
|
@ -94,10 +92,13 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
||||||
User: user.AsAPIUser(),
|
User: user.AsAPIUser(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
if authToken.RefreshToken != nil {
|
||||||
res.RefreshToken = &authToken.RefreshToken.Token
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.RefreshToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,15 +225,6 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.FingerPrintHash, authToken.FingerPrint)
|
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.AccessToken.Token, authToken.FingerPrint)
|
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
|
||||||
res.RefreshToken = &authToken.RefreshToken.Token
|
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.RefreshToken.Token, authToken.FingerPrint)
|
|
||||||
}
|
|
||||||
|
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
|
||||||
go db.Provider.AddSession(models.Session{
|
go db.Provider.AddSession(models.Session{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
UserAgent: utils.GetUserAgent(gc.Request),
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
@ -251,6 +242,15 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
||||||
ExpiresIn: &expiresIn,
|
ExpiresIn: &expiresIn,
|
||||||
User: userToReturn,
|
User: userToReturn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/parsers"
|
"github.com/authorizerdev/authorizer/server/parsers"
|
||||||
|
@ -29,7 +30,7 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenType := params.TokenType
|
tokenType := params.TokenType
|
||||||
if tokenType != "access_token" && tokenType != "refresh_token" && tokenType != "id_token" {
|
if tokenType != constants.TokenTypeAccessToken && tokenType != constants.TokenTypeRefreshToken && tokenType != constants.TokenTypeIdentityToken {
|
||||||
log.Debug("Invalid token type: ", tokenType)
|
log.Debug("Invalid token type: ", tokenType)
|
||||||
return nil, errors.New("invalid token type")
|
return nil, errors.New("invalid token type")
|
||||||
}
|
}
|
||||||
|
@ -38,39 +39,34 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken
|
||||||
var claims jwt.MapClaims
|
var claims jwt.MapClaims
|
||||||
userID := ""
|
userID := ""
|
||||||
nonce := ""
|
nonce := ""
|
||||||
|
|
||||||
|
claims, err = token.ParseJWTToken(params.Token)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to parse JWT token: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
userID = claims["sub"].(string)
|
||||||
|
|
||||||
// access_token and refresh_token should be validated from session store as well
|
// access_token and refresh_token should be validated from session store as well
|
||||||
if tokenType == "access_token" || tokenType == "refresh_token" {
|
if tokenType == constants.TokenTypeAccessToken || tokenType == constants.TokenTypeRefreshToken {
|
||||||
claims, err = token.ParseJWTToken(params.Token)
|
nonce = claims["nonce"].(string)
|
||||||
if err != nil {
|
token, err := memorystore.Provider.GetUserSession(userID, tokenType+"_"+claims["nonce"].(string))
|
||||||
log.Debug("Failed to parse JWT token: ", err)
|
if err != nil || token == "" {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
userID = claims["sub"].(string)
|
|
||||||
nonce, err = memorystore.Provider.GetUserSession(userID, params.Token)
|
|
||||||
if err != nil || nonce == "" {
|
|
||||||
log.Debug("Failed to get user session: ", err)
|
log.Debug("Failed to get user session: ", err)
|
||||||
return nil, errors.New("invalid token")
|
return nil, errors.New("invalid token")
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// for ID token just parse jwt
|
|
||||||
claims, err = token.ParseJWTToken(params.Token)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to parse JWT token: ", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
userID = claims["sub"].(string)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
|
|
||||||
// we cannot validate sub and nonce in case of id_token as that token is not persisted in session store
|
// we cannot validate nonce in case of id_token as that token is not persisted in session store
|
||||||
if userID != "" && nonce != "" {
|
if nonce != "" {
|
||||||
if ok, err := token.ValidateJWTClaims(claims, hostname, nonce, userID); !ok || err != nil {
|
if ok, err := token.ValidateJWTClaims(claims, hostname, nonce, userID); !ok || err != nil {
|
||||||
log.Debug("Failed to parse jwt token: ", err)
|
log.Debug("Failed to parse jwt token: ", err)
|
||||||
return nil, errors.New("invalid claims")
|
return nil, errors.New("invalid claims")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ok, err := token.ValidateJWTTokenWithoutNonce(claims, hostname); !ok || err != nil {
|
if ok, err := token.ValidateJWTTokenWithoutNonce(claims, hostname, userID); !ok || err != nil {
|
||||||
log.Debug("Failed to parse jwt token without nonce: ", err)
|
log.Debug("Failed to parse jwt token without nonce: ", err)
|
||||||
return nil, errors.New("invalid claims")
|
return nil, errors.New("invalid claims")
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
@ -80,15 +81,6 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.FingerPrintHash, authToken.FingerPrint)
|
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.AccessToken.Token, authToken.FingerPrint)
|
|
||||||
|
|
||||||
if authToken.RefreshToken != nil {
|
|
||||||
res.RefreshToken = &authToken.RefreshToken.Token
|
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.RefreshToken.Token, authToken.FingerPrint)
|
|
||||||
}
|
|
||||||
|
|
||||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
|
||||||
go db.Provider.AddSession(models.Session{
|
go db.Provider.AddSession(models.Session{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
UserAgent: utils.GetUserAgent(gc.Request),
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
@ -107,5 +99,14 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
|
||||||
ExpiresIn: &expiresIn,
|
ExpiresIn: &expiresIn,
|
||||||
User: user.AsAPIUser(),
|
User: user.AsAPIUser(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,17 +29,18 @@ func logoutTests(t *testing.T, s TestSetup) {
|
||||||
Token: verificationRequest.Token,
|
Token: verificationRequest.Token,
|
||||||
})
|
})
|
||||||
|
|
||||||
token := *verifyRes.AccessToken
|
accessToken := *verifyRes.AccessToken
|
||||||
sessions, err := memorystore.Provider.GetAllUserSessions(verifyRes.User.ID)
|
assert.NotEmpty(t, accessToken)
|
||||||
|
|
||||||
|
claims, err := token.ParseJWTToken(accessToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, sessions)
|
assert.NotEmpty(t, claims)
|
||||||
cookie := ""
|
|
||||||
// set all they keys in cookie one of them should be session cookie
|
sessionToken, err := memorystore.Provider.GetUserSession(verifyRes.User.ID, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string))
|
||||||
for key := range sessions {
|
assert.NoError(t, err)
|
||||||
if key != token {
|
assert.NotEmpty(t, sessionToken)
|
||||||
cookie += fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", key)
|
|
||||||
}
|
cookie := fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken)
|
||||||
}
|
|
||||||
cookie = strings.TrimSuffix(cookie, ";")
|
cookie = strings.TrimSuffix(cookie, ";")
|
||||||
|
|
||||||
req.Header.Set("Cookie", cookie)
|
req.Header.Set("Cookie", cookie)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -33,17 +34,18 @@ func sessionTests(t *testing.T, s TestSetup) {
|
||||||
Token: verificationRequest.Token,
|
Token: verificationRequest.Token,
|
||||||
})
|
})
|
||||||
|
|
||||||
token := *verifyRes.AccessToken
|
accessToken := *verifyRes.AccessToken
|
||||||
sessions, err := memorystore.Provider.GetAllUserSessions(verifyRes.User.ID)
|
assert.NotEmpty(t, accessToken)
|
||||||
|
|
||||||
|
claims, err := token.ParseJWTToken(accessToken)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, sessions)
|
assert.NotEmpty(t, claims)
|
||||||
cookie := ""
|
|
||||||
// set all they keys in cookie one of them should be session cookie
|
sessionToken, err := memorystore.Provider.GetUserSession(verifyRes.User.ID, constants.TokenTypeSessionToken+"_"+claims["nonce"].(string))
|
||||||
for key := range sessions {
|
assert.NoError(t, err)
|
||||||
if key != token {
|
assert.NotEmpty(t, sessionToken)
|
||||||
cookie += fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", key)
|
|
||||||
}
|
cookie := fmt.Sprintf("%s=%s;", constants.AppCookieName+"_session", sessionToken)
|
||||||
}
|
|
||||||
cookie = strings.TrimSuffix(cookie, ";")
|
cookie = strings.TrimSuffix(cookie, ";")
|
||||||
|
|
||||||
req.Header.Set("Cookie", cookie)
|
req.Header.Set("Cookie", cookie)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
@ -50,9 +51,12 @@ func validateJwtTokenTest(t *testing.T, s TestSetup) {
|
||||||
gc, err := utils.GinContextFromContext(ctx)
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.FingerPrintHash, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.AccessToken.Token, authToken.FingerPrint)
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
memorystore.Provider.SetUserSession(user.ID, authToken.RefreshToken.Token, authToken.FingerPrint)
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
memorystore.Provider.SetUserSession(user.ID, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
|
|
||||||
t.Run(`should validate the access token`, func(t *testing.T) {
|
t.Run(`should validate the access token`, func(t *testing.T) {
|
||||||
res, err := resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{
|
res, err := resolvers.ValidateJwtTokenResolver(ctx, model.ValidateJWTTokenInput{
|
||||||
|
|
|
@ -204,11 +204,16 @@ func ValidateAccessToken(gc *gin.Context, accessToken string) (map[string]interf
|
||||||
}
|
}
|
||||||
|
|
||||||
userID := res["sub"].(string)
|
userID := res["sub"].(string)
|
||||||
nonce, err := memorystore.Provider.GetUserSession(userID, accessToken)
|
nonce := res["nonce"].(string)
|
||||||
|
token, err := memorystore.Provider.GetUserSession(userID, constants.TokenTypeAccessToken+"_"+nonce)
|
||||||
if nonce == "" || err != nil {
|
if nonce == "" || err != nil {
|
||||||
return res, fmt.Errorf(`unauthorized`)
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if token != accessToken {
|
||||||
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
|
}
|
||||||
|
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
if ok, err := ValidateJWTClaims(res, hostname, nonce, userID); !ok || err != nil {
|
if ok, err := ValidateJWTClaims(res, hostname, nonce, userID); !ok || err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
@ -235,11 +240,16 @@ func ValidateRefreshToken(gc *gin.Context, refreshToken string) (map[string]inte
|
||||||
}
|
}
|
||||||
|
|
||||||
userID := res["sub"].(string)
|
userID := res["sub"].(string)
|
||||||
nonce, err := memorystore.Provider.GetUserSession(userID, refreshToken)
|
nonce := res["nonce"].(string)
|
||||||
|
token, err := memorystore.Provider.GetUserSession(userID, constants.TokenTypeRefreshToken+"_"+nonce)
|
||||||
if nonce == "" || err != nil {
|
if nonce == "" || err != nil {
|
||||||
return res, fmt.Errorf(`unauthorized`)
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if token != refreshToken {
|
||||||
|
return res, fmt.Errorf(`unauthorized`)
|
||||||
|
}
|
||||||
|
|
||||||
hostname := parsers.GetHost(gc)
|
hostname := parsers.GetHost(gc)
|
||||||
if ok, err := ValidateJWTClaims(res, hostname, nonce, userID); !ok || err != nil {
|
if ok, err := ValidateJWTClaims(res, hostname, nonce, userID); !ok || err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
@ -268,13 +278,13 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, err := memorystore.Provider.GetUserSession(res.Subject, encryptedSession)
|
token, err := memorystore.Provider.GetUserSession(res.Subject, constants.TokenTypeSessionToken+"_"+res.Nonce)
|
||||||
if nonce == "" || err != nil {
|
if token == "" || err != nil {
|
||||||
log.Debug("invalid browser session:", err)
|
log.Debug("invalid browser session:", err)
|
||||||
return nil, fmt.Errorf(`unauthorized`)
|
return nil, fmt.Errorf(`unauthorized`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.Nonce != nonce {
|
if encryptedSession != token {
|
||||||
return nil, fmt.Errorf(`unauthorized: invalid nonce`)
|
return nil, fmt.Errorf(`unauthorized: invalid nonce`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,8 +145,8 @@ func ValidateJWTClaims(claims jwt.MapClaims, hostname, nonce, subject string) (b
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateJWTClaimsWithoutNonce common util to validate claims without nonce
|
// ValidateJWTTokenWithoutNonce common util to validate claims without nonce
|
||||||
func ValidateJWTTokenWithoutNonce(claims jwt.MapClaims, hostname string) (bool, error) {
|
func ValidateJWTTokenWithoutNonce(claims jwt.MapClaims, hostname, subject string) (bool, error) {
|
||||||
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -159,5 +159,8 @@ func ValidateJWTTokenWithoutNonce(claims jwt.MapClaims, hostname string) (bool,
|
||||||
return false, errors.New("invalid issuer")
|
return false, errors.New("invalid issuer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if claims["sub"] != subject {
|
||||||
|
return false, errors.New("invalid subject")
|
||||||
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user