2022-02-12 10:24:23 +00:00
|
|
|
package token
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
|
2022-06-05 16:14:16 +00:00
|
|
|
"github.com/golang-jwt/jwt"
|
|
|
|
|
2022-02-12 10:24:23 +00:00
|
|
|
"github.com/authorizerdev/authorizer/server/constants"
|
2022-02-28 02:25:01 +00:00
|
|
|
"github.com/authorizerdev/authorizer/server/crypto"
|
2022-05-30 03:49:55 +00:00
|
|
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
2022-02-12 10:24:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// SignJWTToken common util to sing jwt token
|
|
|
|
func SignJWTToken(claims jwt.MapClaims) (string, error) {
|
2022-05-30 05:30:00 +00:00
|
|
|
jwtType, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2022-02-12 10:24:23 +00:00
|
|
|
signingMethod := jwt.GetSigningMethod(jwtType)
|
2022-02-12 13:56:37 +00:00
|
|
|
if signingMethod == nil {
|
|
|
|
return "", errors.New("unsupported signing method")
|
|
|
|
}
|
2022-02-12 10:24:23 +00:00
|
|
|
t := jwt.New(signingMethod)
|
2022-02-12 13:56:37 +00:00
|
|
|
if t == nil {
|
|
|
|
return "", errors.New("unsupported signing method")
|
|
|
|
}
|
2022-02-12 10:24:23 +00:00
|
|
|
t.Claims = claims
|
|
|
|
|
|
|
|
switch signingMethod {
|
|
|
|
case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512:
|
2022-05-30 05:30:00 +00:00
|
|
|
jwtSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return t.SignedString([]byte(jwtSecret))
|
2022-02-12 10:24:23 +00:00
|
|
|
case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512:
|
2022-05-30 05:30:00 +00:00
|
|
|
jwtPrivateKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPrivateKey)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
key, err := crypto.ParseRsaPrivateKeyFromPemStr(jwtPrivateKey)
|
2022-02-12 10:24:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return t.SignedString(key)
|
|
|
|
case jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512:
|
2022-05-30 05:30:00 +00:00
|
|
|
jwtPrivateKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPrivateKey)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
key, err := crypto.ParseEcdsaPrivateKeyFromPemStr(jwtPrivateKey)
|
2022-02-12 10:24:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2022-02-28 02:25:01 +00:00
|
|
|
|
2022-02-12 10:24:23 +00:00
|
|
|
return t.SignedString(key)
|
|
|
|
default:
|
|
|
|
return "", errors.New("unsupported signing method")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParseJWTToken common util to parse jwt token
|
2022-06-11 13:40:39 +00:00
|
|
|
func ParseJWTToken(token string) (jwt.MapClaims, error) {
|
2022-05-30 05:30:00 +00:00
|
|
|
jwtType, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-02-12 10:24:23 +00:00
|
|
|
signingMethod := jwt.GetSigningMethod(jwtType)
|
|
|
|
|
|
|
|
var claims jwt.MapClaims
|
|
|
|
|
|
|
|
switch signingMethod {
|
|
|
|
case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512:
|
2022-02-12 13:56:37 +00:00
|
|
|
_, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) {
|
2022-05-30 05:30:00 +00:00
|
|
|
jwtSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return []byte(jwtSecret), nil
|
2022-02-12 10:24:23 +00:00
|
|
|
})
|
|
|
|
case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512:
|
|
|
|
_, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) {
|
2022-05-30 05:30:00 +00:00
|
|
|
jwtPublicKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
key, err := crypto.ParseRsaPublicKeyFromPemStr(jwtPublicKey)
|
2022-02-12 10:24:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return key, nil
|
|
|
|
})
|
|
|
|
case jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512:
|
|
|
|
_, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) {
|
2022-05-30 05:30:00 +00:00
|
|
|
jwtPublicKey, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
key, err := crypto.ParseEcdsaPublicKeyFromPemStr(jwtPublicKey)
|
2022-02-12 10:24:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return key, nil
|
|
|
|
})
|
|
|
|
default:
|
|
|
|
err = errors.New("unsupported signing method")
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return claims, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// claim parses exp & iat into float 64 with e^10,
|
|
|
|
// but we expect it to be int64
|
|
|
|
// hence we need to assert interface and convert to int64
|
|
|
|
intExp := int64(claims["exp"].(float64))
|
|
|
|
intIat := int64(claims["iat"].(float64))
|
|
|
|
claims["exp"] = intExp
|
|
|
|
claims["iat"] = intIat
|
2022-06-11 13:40:39 +00:00
|
|
|
|
|
|
|
return claims, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ValidateJWTClaims common util to validate claims
|
|
|
|
func ValidateJWTClaims(claims jwt.MapClaims, hostname, nonce, subject string) (bool, error) {
|
2022-05-30 05:30:00 +00:00
|
|
|
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
|
|
|
if err != nil {
|
2022-06-11 13:40:39 +00:00
|
|
|
return false, err
|
2022-05-30 05:30:00 +00:00
|
|
|
}
|
|
|
|
if claims["aud"] != clientID {
|
2022-06-11 13:40:39 +00:00
|
|
|
return false, errors.New("invalid audience")
|
2022-03-02 12:12:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if claims["nonce"] != nonce {
|
2022-06-11 13:40:39 +00:00
|
|
|
return false, errors.New("invalid nonce")
|
2022-03-02 12:12:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if claims["iss"] != hostname {
|
2022-06-11 13:40:39 +00:00
|
|
|
return false, errors.New("invalid issuer")
|
2022-03-02 12:12:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if claims["sub"] != subject {
|
2022-06-11 13:40:39 +00:00
|
|
|
return false, errors.New("invalid subject")
|
2022-03-02 12:12:31 +00:00
|
|
|
}
|
|
|
|
|
2022-06-11 13:40:39 +00:00
|
|
|
return true, nil
|
2022-02-12 10:24:23 +00:00
|
|
|
}
|
2022-03-24 08:01:56 +00:00
|
|
|
|
2022-06-11 18:57:21 +00:00
|
|
|
// ValidateJWTTokenWithoutNonce common util to validate claims without nonce
|
|
|
|
func ValidateJWTTokenWithoutNonce(claims jwt.MapClaims, hostname, subject string) (bool, error) {
|
2022-05-30 05:30:00 +00:00
|
|
|
clientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyClientID)
|
|
|
|
if err != nil {
|
2022-06-11 13:40:39 +00:00
|
|
|
return false, err
|
2022-05-30 05:30:00 +00:00
|
|
|
}
|
|
|
|
if claims["aud"] != clientID {
|
2022-06-11 13:40:39 +00:00
|
|
|
return false, errors.New("invalid audience")
|
2022-03-24 08:01:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if claims["iss"] != hostname {
|
2022-06-11 13:40:39 +00:00
|
|
|
return false, errors.New("invalid issuer")
|
2022-03-24 08:01:56 +00:00
|
|
|
}
|
|
|
|
|
2022-06-11 18:57:21 +00:00
|
|
|
if claims["sub"] != subject {
|
|
|
|
return false, errors.New("invalid subject")
|
|
|
|
}
|
2022-06-11 13:40:39 +00:00
|
|
|
return true, nil
|
2022-03-24 08:01:56 +00:00
|
|
|
}
|