fix: update_env resolver

This commit is contained in:
Lakhan Samani 2022-02-26 20:36:22 +05:30
parent 145091dce1
commit b68d9ce661
14 changed files with 298 additions and 74 deletions

View File

@ -59,8 +59,6 @@ const (
EnvKeyAdminCookieName = "ADMIN_COOKIE_NAME" EnvKeyAdminCookieName = "ADMIN_COOKIE_NAME"
// EnvKeyResetPasswordURL key for env variable RESET_PASSWORD_URL // EnvKeyResetPasswordURL key for env variable RESET_PASSWORD_URL
EnvKeyResetPasswordURL = "RESET_PASSWORD_URL" EnvKeyResetPasswordURL = "RESET_PASSWORD_URL"
// EnvKeyEncryptionKey key for env variable ENCRYPTION_KEY
EnvKeyEncryptionKey = "ENCRYPTION_KEY"
// EnvKeyDisableEmailVerification key for env variable DISABLE_EMAIL_VERIFICATION // EnvKeyDisableEmailVerification key for env variable DISABLE_EMAIL_VERIFICATION
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION" EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH // EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
@ -99,6 +97,8 @@ const (
// Not Exposed Keys // Not Exposed Keys
// EnvKeyClientID key for env variable CLIENT_ID // EnvKeyClientID key for env variable CLIENT_ID
EnvKeyClientID = "CLIENT_ID" EnvKeyClientID = "CLIENT_ID"
// EnvKeyEncryptionKey key for env variable ENCRYPTION_KEY
EnvKeyEncryptionKey = "ENCRYPTION_KEY"
// EnvKeyJWK key for env variable JWK // EnvKeyJWK key for env variable JWK
EnvKeyJWK = "JWK" EnvKeyJWK = "JWK"
// EnvKeyIsProd key for env variable IS_PROD // EnvKeyIsProd key for env variable IS_PROD

View File

@ -3,6 +3,8 @@ package crypto
import ( import (
"crypto/x509" "crypto/x509"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"gopkg.in/square/go-jose.v2" "gopkg.in/square/go-jose.v2"
) )
@ -27,3 +29,45 @@ func GetPubJWK(algo, keyID string, publicKey interface{}) (string, error) {
} }
return string(jwkPublicKey), nil return string(jwkPublicKey), nil
} }
// GenerateJWKBasedOnEnv generates JWK based on env
func GenerateJWKBasedOnEnv() (string, error) {
jwk := ""
algo := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType)
clientID := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID)
var err error
// check if jwt secret is provided
if IsHMACA(algo) {
jwk, err = GetPubJWK(algo, clientID, []byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)))
if err != nil {
return "", err
}
}
if IsRSA(algo) {
publicKeyInstance, err := ParseRsaPublicKeyFromPemStr(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey))
if err != nil {
return "", err
}
jwk, err = GetPubJWK(algo, clientID, publicKeyInstance)
if err != nil {
return "", err
}
}
if IsECDSA(algo) {
publicKeyInstance, err := ParseEcdsaPublicKeyFromPemStr(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey))
if err != nil {
return "", err
}
jwk, err = GetPubJWK(algo, clientID, publicKeyInstance)
if err != nil {
return "", err
}
}
return jwk, nil
}

30
server/env/env.go vendored
View File

@ -148,24 +148,20 @@ func InitAllEnv() error {
} }
} }
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" && crypto.IsHMACA(algo) { if crypto.IsHMACA(algo) {
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret) envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret)
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" { if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
envData.StringEnv[constants.EnvKeyJwtSecret], envData.StringEnv[constants.EnvKeyJWK], err = crypto.NewHMACKey(algo, clientID) envData.StringEnv[constants.EnvKeyJwtSecret], _, err = crypto.NewHMACKey(algo, clientID)
if err != nil { if err != nil {
return err return err
} }
} else {
envData.StringEnv[constants.EnvKeyJWK], err = crypto.GetPubJWK(algo, clientID, []byte(envData.StringEnv[constants.EnvKeyJwtSecret]))
if err != nil {
return err
} }
} }
} }
if crypto.IsRSA(algo) || crypto.IsECDSA(algo) { if crypto.IsRSA(algo) || crypto.IsECDSA(algo) {
privateKey, publicKey, jwk := "", "", "" privateKey, publicKey := "", ""
if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" { if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" {
privateKey = os.Getenv(constants.EnvKeyJwtPrivateKey) privateKey = os.Getenv(constants.EnvKeyJwtPrivateKey)
@ -179,12 +175,12 @@ func InitAllEnv() error {
// if either of them is not present generate new keys // if either of them is not present generate new keys
if privateKey == "" || publicKey == "" { if privateKey == "" || publicKey == "" {
if crypto.IsRSA(algo) { if crypto.IsRSA(algo) {
_, privateKey, publicKey, jwk, err = crypto.NewRSAKey(algo, clientID) _, privateKey, publicKey, _, err = crypto.NewRSAKey(algo, clientID)
if err != nil { if err != nil {
return err return err
} }
} else if crypto.IsECDSA(algo) { } else if crypto.IsECDSA(algo) {
_, privateKey, publicKey, jwk, err = crypto.NewECDSAKey(algo, clientID) _, privateKey, publicKey, _, err = crypto.NewECDSAKey(algo, clientID)
if err != nil { if err != nil {
return err return err
} }
@ -197,34 +193,24 @@ func InitAllEnv() error {
return err return err
} }
publicKeyInstance, err := crypto.ParseRsaPublicKeyFromPemStr(publicKey) _, err := crypto.ParseRsaPublicKeyFromPemStr(publicKey)
if err != nil { if err != nil {
return err return err
} }
jwk, err = crypto.GetPubJWK(algo, clientID, publicKeyInstance)
if err != nil {
return err
}
} else if crypto.IsECDSA(algo) { } else if crypto.IsECDSA(algo) {
_, err = crypto.ParseEcdsaPrivateKeyFromPemStr(privateKey) _, err = crypto.ParseEcdsaPrivateKeyFromPemStr(privateKey)
if err != nil { if err != nil {
return err return err
} }
publicKeyInstance, err := crypto.ParseEcdsaPublicKeyFromPemStr(publicKey) _, err := crypto.ParseEcdsaPublicKeyFromPemStr(publicKey)
if err != nil {
return err
}
jwk, err = crypto.GetPubJWK(algo, clientID, publicKeyInstance)
if err != nil { if err != nil {
return err return err
} }
} }
} }
envData.StringEnv[constants.EnvKeyJWK] = jwk
envData.StringEnv[constants.EnvKeyJwtPrivateKey] = privateKey envData.StringEnv[constants.EnvKeyJwtPrivateKey] = privateKey
envData.StringEnv[constants.EnvKeyJwtPublicKey] = publicKey envData.StringEnv[constants.EnvKeyJwtPublicKey] = publicKey

View File

@ -7,12 +7,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/google/uuid"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"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"
"github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/google/uuid"
) )
// GetEnvData returns the env data from database // GetEnvData returns the env data from database
@ -107,7 +109,8 @@ func PersistEnv() error {
hasChanged := false hasChanged := false
for key, value := range storeData.StringEnv { for key, value := range storeData.StringEnv {
if key != constants.EnvKeyEncryptionKey { // don't override unexposed envs
if key != constants.EnvKeyEncryptionKey && key != constants.EnvKeyClientID && key != constants.EnvKeyJWK {
// check only for derivative keys // check only for derivative keys
// No need to check for ENCRYPTION_KEY which special key we use for encrypting config data // No need to check for ENCRYPTION_KEY which special key we use for encrypting config data
// as we have removed it from json // as we have removed it from json
@ -160,8 +163,13 @@ func PersistEnv() error {
hasChanged = true hasChanged = true
} }
} }
envstore.EnvInMemoryStoreObj.UpdateEnvStore(storeData) envstore.EnvInMemoryStoreObj.UpdateEnvStore(storeData)
jwk, err := crypto.GenerateJWKBasedOnEnv()
if err != nil {
return err
}
// updating jwk
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJWK, jwk)
if hasChanged { if hasChanged {
encryptedConfig, err := utils.EncryptEnvData(storeData) encryptedConfig, err := utils.EncryptEnvData(storeData)

View File

@ -30,7 +30,7 @@ require (
google.golang.org/protobuf v1.27.1 // indirect google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/mail.v2 v2.3.1 gopkg.in/mail.v2 v2.3.1
gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/mysql v1.2.1 gorm.io/driver/mysql v1.2.1
gorm.io/driver/postgres v1.2.3 gorm.io/driver/postgres v1.2.3

View File

@ -69,9 +69,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4= github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI= github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI=
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
@ -109,8 +106,6 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.9.4 h1:L8MLKG2mvVXiQu07qB6hmfqeSYQdOnqPot2GhsIwIaI=
github.com/goccy/go-json v0.9.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@ -261,18 +256,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4=
github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ=
github.com/lestrrat-go/httpcc v1.0.0 h1:FszVC6cKfDvBKcJv646+lkh4GydQg2Z29scgUfkOpYc=
github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE=
github.com/lestrrat-go/iter v1.0.1 h1:q8faalr2dY6o8bV45uwrxq12bRa1ezKrB6oM9FUgN4A=
github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc=
github.com/lestrrat-go/jwx v1.2.19 h1:qxxLmAXNwZpTTvjc4PH21nT7I4wPK6lVv3lVNcZPnUk=
github.com/lestrrat-go/jwx v1.2.19/go.mod h1:bWTBO7IHHVMtNunM8so9MT8wD+euEY1PzGEyCnuI2qM=
github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@ -403,7 +386,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
@ -700,7 +682,6 @@ gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ= gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=

View File

@ -54,6 +54,7 @@ type ComplexityRoot struct {
AdminSecret func(childComplexity int) int AdminSecret func(childComplexity int) int
AllowedOrigins func(childComplexity int) int AllowedOrigins func(childComplexity int) int
AppURL func(childComplexity int) int AppURL func(childComplexity int) int
ClientID func(childComplexity int) int
CookieName func(childComplexity int) int CookieName func(childComplexity int) int
CustomAccessTokenScript func(childComplexity int) int CustomAccessTokenScript func(childComplexity int) int
DatabaseName func(childComplexity int) int DatabaseName func(childComplexity int) int
@ -94,6 +95,7 @@ type ComplexityRoot struct {
} }
Meta struct { Meta struct {
ClientID func(childComplexity int) int
IsBasicAuthenticationEnabled func(childComplexity int) int IsBasicAuthenticationEnabled func(childComplexity int) int
IsEmailVerificationEnabled func(childComplexity int) int IsEmailVerificationEnabled func(childComplexity int) int
IsFacebookLoginEnabled func(childComplexity int) int IsFacebookLoginEnabled func(childComplexity int) int
@ -281,6 +283,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Env.AppURL(childComplexity), true return e.complexity.Env.AppURL(childComplexity), true
case "Env.CLIENT_ID":
if e.complexity.Env.ClientID == nil {
break
}
return e.complexity.Env.ClientID(childComplexity), true
case "Env.COOKIE_NAME": case "Env.COOKIE_NAME":
if e.complexity.Env.CookieName == nil { if e.complexity.Env.CookieName == nil {
break break
@ -519,6 +528,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Error.Reason(childComplexity), true return e.complexity.Error.Reason(childComplexity), true
case "Meta.client_id":
if e.complexity.Meta.ClientID == nil {
break
}
return e.complexity.Meta.ClientID(childComplexity), true
case "Meta.is_basic_authentication_enabled": case "Meta.is_basic_authentication_enabled":
if e.complexity.Meta.IsBasicAuthenticationEnabled == nil { if e.complexity.Meta.IsBasicAuthenticationEnabled == nil {
break break
@ -1139,6 +1155,7 @@ type Pagination {
type Meta { type Meta {
version: String! version: String!
client_id: String!
is_google_login_enabled: Boolean! is_google_login_enabled: Boolean!
is_facebook_login_enabled: Boolean! is_facebook_login_enabled: Boolean!
is_github_login_enabled: Boolean! is_github_login_enabled: Boolean!
@ -1211,9 +1228,10 @@ type ValidJWTResponse {
type Env { type Env {
ADMIN_SECRET: String ADMIN_SECRET: String
DATABASE_NAME: String DATABASE_NAME: String!
DATABASE_URL: String DATABASE_URL: String!
DATABASE_TYPE: String DATABASE_TYPE: String!
CLIENT_ID: String!
CUSTOM_ACCESS_TOKEN_SCRIPT: String CUSTOM_ACCESS_TOKEN_SCRIPT: String
SMTP_HOST: String SMTP_HOST: String
SMTP_PORT: String SMTP_PORT: String
@ -1922,11 +1940,14 @@ func (ec *executionContext) _Env_DATABASE_NAME(ctx context.Context, field graphq
return graphql.Null return graphql.Null
} }
if resTmp == nil { if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null return graphql.Null
} }
res := resTmp.(*string) res := resTmp.(string)
fc.Result = res fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res) return ec.marshalNString2string(ctx, field.Selections, res)
} }
func (ec *executionContext) _Env_DATABASE_URL(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { func (ec *executionContext) _Env_DATABASE_URL(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
@ -1954,11 +1975,14 @@ func (ec *executionContext) _Env_DATABASE_URL(ctx context.Context, field graphql
return graphql.Null return graphql.Null
} }
if resTmp == nil { if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null return graphql.Null
} }
res := resTmp.(*string) res := resTmp.(string)
fc.Result = res fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res) return ec.marshalNString2string(ctx, field.Selections, res)
} }
func (ec *executionContext) _Env_DATABASE_TYPE(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { func (ec *executionContext) _Env_DATABASE_TYPE(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
@ -1986,11 +2010,49 @@ func (ec *executionContext) _Env_DATABASE_TYPE(ctx context.Context, field graphq
return graphql.Null return graphql.Null
} }
if resTmp == nil { if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null return graphql.Null
} }
res := resTmp.(*string) res := resTmp.(string)
fc.Result = res fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res) return ec.marshalNString2string(ctx, field.Selections, res)
}
func (ec *executionContext) _Env_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Env",
Field: field,
Args: nil,
IsMethod: false,
IsResolver: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.ClientID, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
fc.Result = res
return ec.marshalNString2string(ctx, field.Selections, res)
} }
func (ec *executionContext) _Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { func (ec *executionContext) _Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
@ -3090,6 +3152,41 @@ func (ec *executionContext) _Meta_version(ctx context.Context, field graphql.Col
return ec.marshalNString2string(ctx, field.Selections, res) return ec.marshalNString2string(ctx, field.Selections, res)
} }
func (ec *executionContext) _Meta_client_id(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Meta",
Field: field,
Args: nil,
IsMethod: false,
IsResolver: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.ClientID, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(string)
fc.Result = res
return ec.marshalNString2string(ctx, field.Selections, res)
}
func (ec *executionContext) _Meta_is_google_login_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) { func (ec *executionContext) _Meta_is_google_login_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -7619,10 +7716,24 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
out.Values[i] = ec._Env_ADMIN_SECRET(ctx, field, obj) out.Values[i] = ec._Env_ADMIN_SECRET(ctx, field, obj)
case "DATABASE_NAME": case "DATABASE_NAME":
out.Values[i] = ec._Env_DATABASE_NAME(ctx, field, obj) out.Values[i] = ec._Env_DATABASE_NAME(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "DATABASE_URL": case "DATABASE_URL":
out.Values[i] = ec._Env_DATABASE_URL(ctx, field, obj) out.Values[i] = ec._Env_DATABASE_URL(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "DATABASE_TYPE": case "DATABASE_TYPE":
out.Values[i] = ec._Env_DATABASE_TYPE(ctx, field, obj) out.Values[i] = ec._Env_DATABASE_TYPE(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "CLIENT_ID":
out.Values[i] = ec._Env_CLIENT_ID(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "CUSTOM_ACCESS_TOKEN_SCRIPT": case "CUSTOM_ACCESS_TOKEN_SCRIPT":
out.Values[i] = ec._Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx, field, obj) out.Values[i] = ec._Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx, field, obj)
case "SMTP_HOST": case "SMTP_HOST":
@ -7744,6 +7855,11 @@ func (ec *executionContext) _Meta(ctx context.Context, sel ast.SelectionSet, obj
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
invalids++ invalids++
} }
case "client_id":
out.Values[i] = ec._Meta_client_id(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "is_google_login_enabled": case "is_google_login_enabled":
out.Values[i] = ec._Meta_is_google_login_enabled(ctx, field, obj) out.Values[i] = ec._Meta_is_google_login_enabled(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {

View File

@ -23,9 +23,10 @@ type DeleteUserInput struct {
type Env struct { type Env struct {
AdminSecret *string `json:"ADMIN_SECRET"` AdminSecret *string `json:"ADMIN_SECRET"`
DatabaseName *string `json:"DATABASE_NAME"` DatabaseName string `json:"DATABASE_NAME"`
DatabaseURL *string `json:"DATABASE_URL"` DatabaseURL string `json:"DATABASE_URL"`
DatabaseType *string `json:"DATABASE_TYPE"` DatabaseType string `json:"DATABASE_TYPE"`
ClientID string `json:"CLIENT_ID"`
CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT"` CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT"`
SMTPHost *string `json:"SMTP_HOST"` SMTPHost *string `json:"SMTP_HOST"`
SMTPPort *string `json:"SMTP_PORT"` SMTPPort *string `json:"SMTP_PORT"`
@ -86,6 +87,7 @@ type MagicLinkLoginInput struct {
type Meta struct { type Meta struct {
Version string `json:"version"` Version string `json:"version"`
ClientID string `json:"client_id"`
IsGoogleLoginEnabled bool `json:"is_google_login_enabled"` IsGoogleLoginEnabled bool `json:"is_google_login_enabled"`
IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"` IsFacebookLoginEnabled bool `json:"is_facebook_login_enabled"`
IsGithubLoginEnabled bool `json:"is_github_login_enabled"` IsGithubLoginEnabled bool `json:"is_github_login_enabled"`

View File

@ -14,6 +14,7 @@ type Pagination {
type Meta { type Meta {
version: String! version: String!
client_id: String!
is_google_login_enabled: Boolean! is_google_login_enabled: Boolean!
is_facebook_login_enabled: Boolean! is_facebook_login_enabled: Boolean!
is_github_login_enabled: Boolean! is_github_login_enabled: Boolean!
@ -86,9 +87,10 @@ type ValidJWTResponse {
type Env { type Env {
ADMIN_SECRET: String ADMIN_SECRET: String
DATABASE_NAME: String DATABASE_NAME: String!
DATABASE_URL: String DATABASE_URL: String!
DATABASE_TYPE: String DATABASE_TYPE: String!
CLIENT_ID: String!
CUSTOM_ACCESS_TOKEN_SCRIPT: String CUSTOM_ACCESS_TOKEN_SCRIPT: String
SMTP_HOST: String SMTP_HOST: String
SMTP_PORT: String SMTP_PORT: String

View File

@ -9,9 +9,18 @@ import (
) )
func JWKsHandler() gin.HandlerFunc { func JWKsHandler() gin.HandlerFunc {
var data map[string]string
json.Unmarshal([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJWK)), &data)
return func(c *gin.Context) { return func(c *gin.Context) {
var data map[string]string
jwk := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJWK)
err := json.Unmarshal([]byte(jwk), &data)
if err != nil {
c.JSON(500, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, gin.H{ c.JSON(200, gin.H{
"keys": []map[string]string{ "keys": []map[string]string{
data, data,

View File

@ -28,6 +28,7 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
// get clone of store // get clone of store
store := envstore.EnvInMemoryStoreObj.GetEnvStoreClone() store := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
adminSecret := store.StringEnv[constants.EnvKeyAdminSecret] adminSecret := store.StringEnv[constants.EnvKeyAdminSecret]
clientID := store.StringEnv[constants.EnvKeyClientID]
databaseURL := store.StringEnv[constants.EnvKeyDatabaseURL] databaseURL := store.StringEnv[constants.EnvKeyDatabaseURL]
databaseName := store.StringEnv[constants.EnvKeyDatabaseName] databaseName := store.StringEnv[constants.EnvKeyDatabaseName]
databaseType := store.StringEnv[constants.EnvKeyDatabaseType] databaseType := store.StringEnv[constants.EnvKeyDatabaseType]
@ -65,9 +66,10 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
res = &model.Env{ res = &model.Env{
AdminSecret: &adminSecret, AdminSecret: &adminSecret,
DatabaseName: &databaseName, DatabaseName: databaseName,
DatabaseURL: &databaseURL, DatabaseURL: databaseURL,
DatabaseType: &databaseType, DatabaseType: databaseType,
ClientID: clientID,
CustomAccessTokenScript: &customAccessTokenScript, CustomAccessTokenScript: &customAccessTokenScript,
SMTPHost: &smtpHost, SMTPHost: &smtpHost,
SMTPPort: &smtpPort, SMTPPort: &smtpPort,

View File

@ -10,6 +10,7 @@ import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
@ -33,6 +34,66 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
return res, fmt.Errorf("unauthorized") return res, fmt.Errorf("unauthorized")
} }
updatedData := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
isJWTUpdated := false
algo := updatedData.StringEnv[constants.EnvKeyJwtType]
if params.JwtType != nil {
algo = *params.JwtType
if !crypto.IsHMACA(algo) && !crypto.IsECDSA(algo) && !crypto.IsRSA(algo) {
return res, fmt.Errorf("invalid jwt type")
}
updatedData.StringEnv[constants.EnvKeyJwtType] = algo
isJWTUpdated = true
}
if params.JwtSecret != nil || params.JwtPublicKey != nil || params.JwtPrivateKey != nil {
isJWTUpdated = true
}
if isJWTUpdated {
// check if jwt secret is provided
if crypto.IsHMACA(algo) {
if params.JwtSecret == nil {
return res, fmt.Errorf("jwt secret is required for HMAC algorithm")
}
}
if crypto.IsRSA(algo) {
if params.JwtPrivateKey == nil || params.JwtPublicKey == nil {
return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm")
}
_, err = crypto.ParseRsaPrivateKeyFromPemStr(*params.JwtPrivateKey)
if err != nil {
return res, err
}
_, err := crypto.ParseRsaPublicKeyFromPemStr(*params.JwtPublicKey)
if err != nil {
return res, err
}
}
if crypto.IsECDSA(algo) {
if params.JwtPrivateKey == nil || params.JwtPublicKey == nil {
return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm")
}
_, err = crypto.ParseEcdsaPrivateKeyFromPemStr(*params.JwtPrivateKey)
if err != nil {
return res, err
}
_, err := crypto.ParseEcdsaPublicKeyFromPemStr(*params.JwtPublicKey)
if err != nil {
return res, err
}
}
}
var data map[string]interface{} var data map[string]interface{}
byteData, err := json.Marshal(params) byteData, err := json.Marshal(params)
if err != nil { if err != nil {
@ -61,7 +122,6 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
} }
updatedData := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
for key, value := range data { for key, value := range data {
if value != nil { if value != nil {
fieldType := reflect.TypeOf(value).String() fieldType := reflect.TypeOf(value).String()
@ -117,8 +177,20 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
// Update local store // Update local store
envstore.EnvInMemoryStoreObj.UpdateEnvStore(updatedData) envstore.EnvInMemoryStoreObj.UpdateEnvStore(updatedData)
sessionstore.InitSession() jwk, err := crypto.GenerateJWKBasedOnEnv()
oauth.InitOAuth() if err != nil {
return res, err
}
// updating jwk
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJWK, jwk)
err = sessionstore.InitSession()
if err != nil {
return res, err
}
err = oauth.InitOAuth()
if err != nil {
return res, err
}
// Fetch the current db store and update it // Fetch the current db store and update it
env, err := db.Provider.GetEnv() env, err := db.Provider.GetEnv()

View File

@ -33,6 +33,7 @@ func TestResolvers(t *testing.T) {
envData.EnvData = "" envData.EnvData = ""
db.Provider.UpdateEnv(envData) db.Provider.UpdateEnv(envData)
} }
env.InitAllEnv()
env.PersistEnv() env.PersistEnv()
t.Run("should pass tests for "+dbType, func(t *testing.T) { t.Run("should pass tests for "+dbType, func(t *testing.T) {

View File

@ -10,6 +10,7 @@ import (
func GetMetaInfo() model.Meta { func GetMetaInfo() model.Meta {
return model.Meta{ return model.Meta{
Version: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyVersion), Version: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyVersion),
ClientID: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID),
IsGoogleLoginEnabled: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientID) != "" && envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientSecret) != "", IsGoogleLoginEnabled: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientID) != "" && envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGoogleClientSecret) != "",
IsGithubLoginEnabled: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGithubClientID) != "" && envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGithubClientSecret) != "", IsGithubLoginEnabled: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGithubClientID) != "" && envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyGithubClientSecret) != "",
IsFacebookLoginEnabled: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientID) != "" && envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientSecret) != "", IsFacebookLoginEnabled: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientID) != "" && envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyFacebookClientSecret) != "",