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"
// EnvKeyResetPasswordURL key for env variable 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 = "DISABLE_EMAIL_VERIFICATION"
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
@ -99,6 +97,8 @@ const (
// Not Exposed Keys
// EnvKeyClientID key for env variable CLIENT_ID
EnvKeyClientID = "CLIENT_ID"
// EnvKeyEncryptionKey key for env variable ENCRYPTION_KEY
EnvKeyEncryptionKey = "ENCRYPTION_KEY"
// EnvKeyJWK key for env variable JWK
EnvKeyJWK = "JWK"
// EnvKeyIsProd key for env variable IS_PROD

View File

@ -3,6 +3,8 @@ package crypto
import (
"crypto/x509"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore"
"gopkg.in/square/go-jose.v2"
)
@ -27,3 +29,45 @@ func GetPubJWK(algo, keyID string, publicKey interface{}) (string, error) {
}
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
}

38
server/env/env.go vendored
View File

@ -148,24 +148,20 @@ func InitAllEnv() error {
}
}
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" && crypto.IsHMACA(algo) {
envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret)
if crypto.IsHMACA(algo) {
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
envData.StringEnv[constants.EnvKeyJwtSecret], envData.StringEnv[constants.EnvKeyJWK], err = crypto.NewHMACKey(algo, clientID)
if err != nil {
return err
envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret)
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
envData.StringEnv[constants.EnvKeyJwtSecret], _, err = crypto.NewHMACKey(algo, clientID)
if err != nil {
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) {
privateKey, publicKey, jwk := "", "", ""
privateKey, publicKey := "", ""
if envData.StringEnv[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 privateKey == "" || publicKey == "" {
if crypto.IsRSA(algo) {
_, privateKey, publicKey, jwk, err = crypto.NewRSAKey(algo, clientID)
_, privateKey, publicKey, _, err = crypto.NewRSAKey(algo, clientID)
if err != nil {
return err
}
} else if crypto.IsECDSA(algo) {
_, privateKey, publicKey, jwk, err = crypto.NewECDSAKey(algo, clientID)
_, privateKey, publicKey, _, err = crypto.NewECDSAKey(algo, clientID)
if err != nil {
return err
}
@ -197,34 +193,24 @@ func InitAllEnv() error {
return err
}
publicKeyInstance, err := crypto.ParseRsaPublicKeyFromPemStr(publicKey)
_, err := crypto.ParseRsaPublicKeyFromPemStr(publicKey)
if err != nil {
return err
}
jwk, err = crypto.GetPubJWK(algo, clientID, publicKeyInstance)
if err != nil {
return err
}
} else if crypto.IsECDSA(algo) {
_, err = crypto.ParseEcdsaPrivateKeyFromPemStr(privateKey)
if err != nil {
return err
}
publicKeyInstance, err := crypto.ParseEcdsaPublicKeyFromPemStr(publicKey)
if err != nil {
return err
}
jwk, err = crypto.GetPubJWK(algo, clientID, publicKeyInstance)
_, err := crypto.ParseEcdsaPublicKeyFromPemStr(publicKey)
if err != nil {
return err
}
}
}
envData.StringEnv[constants.EnvKeyJWK] = jwk
envData.StringEnv[constants.EnvKeyJwtPrivateKey] = privateKey
envData.StringEnv[constants.EnvKeyJwtPublicKey] = publicKey

View File

@ -7,12 +7,14 @@ import (
"strconv"
"strings"
"github.com/google/uuid"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/db/models"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/google/uuid"
)
// GetEnvData returns the env data from database
@ -107,7 +109,8 @@ func PersistEnv() error {
hasChanged := false
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
// No need to check for ENCRYPTION_KEY which special key we use for encrypting config data
// as we have removed it from json
@ -160,8 +163,13 @@ func PersistEnv() error {
hasChanged = true
}
}
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 {
encryptedConfig, err := utils.EncryptEnvData(storeData)

View File

@ -30,7 +30,7 @@ require (
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
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
gorm.io/driver/mysql v1.2.1
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
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-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
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/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
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.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
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.1.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-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-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-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
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/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
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.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
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
AllowedOrigins func(childComplexity int) int
AppURL func(childComplexity int) int
ClientID func(childComplexity int) int
CookieName func(childComplexity int) int
CustomAccessTokenScript func(childComplexity int) int
DatabaseName func(childComplexity int) int
@ -94,6 +95,7 @@ type ComplexityRoot struct {
}
Meta struct {
ClientID func(childComplexity int) int
IsBasicAuthenticationEnabled func(childComplexity int) int
IsEmailVerificationEnabled 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
case "Env.CLIENT_ID":
if e.complexity.Env.ClientID == nil {
break
}
return e.complexity.Env.ClientID(childComplexity), true
case "Env.COOKIE_NAME":
if e.complexity.Env.CookieName == nil {
break
@ -519,6 +528,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
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":
if e.complexity.Meta.IsBasicAuthenticationEnabled == nil {
break
@ -1139,6 +1155,7 @@ type Pagination {
type Meta {
version: String!
client_id: String!
is_google_login_enabled: Boolean!
is_facebook_login_enabled: Boolean!
is_github_login_enabled: Boolean!
@ -1211,9 +1228,10 @@ type ValidJWTResponse {
type Env {
ADMIN_SECRET: String
DATABASE_NAME: String
DATABASE_URL: String
DATABASE_TYPE: String
DATABASE_NAME: String!
DATABASE_URL: String!
DATABASE_TYPE: String!
CLIENT_ID: String!
CUSTOM_ACCESS_TOKEN_SCRIPT: String
SMTP_HOST: String
SMTP_PORT: String
@ -1922,11 +1940,14 @@ func (ec *executionContext) _Env_DATABASE_NAME(ctx context.Context, field graphq
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*string)
res := resTmp.(string)
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) {
@ -1954,11 +1975,14 @@ func (ec *executionContext) _Env_DATABASE_URL(ctx context.Context, field graphql
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*string)
res := resTmp.(string)
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) {
@ -1986,11 +2010,49 @@ func (ec *executionContext) _Env_DATABASE_TYPE(ctx context.Context, field graphq
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*string)
res := resTmp.(string)
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) {
@ -3090,6 +3152,41 @@ func (ec *executionContext) _Meta_version(ctx context.Context, field graphql.Col
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) {
defer func() {
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)
case "DATABASE_NAME":
out.Values[i] = ec._Env_DATABASE_NAME(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "DATABASE_URL":
out.Values[i] = ec._Env_DATABASE_URL(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "DATABASE_TYPE":
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":
out.Values[i] = ec._Env_CUSTOM_ACCESS_TOKEN_SCRIPT(ctx, field, obj)
case "SMTP_HOST":
@ -7744,6 +7855,11 @@ func (ec *executionContext) _Meta(ctx context.Context, sel ast.SelectionSet, obj
if out.Values[i] == graphql.Null {
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":
out.Values[i] = ec._Meta_is_google_login_enabled(ctx, field, obj)
if out.Values[i] == graphql.Null {

View File

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

View File

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

View File

@ -9,9 +9,18 @@ import (
)
func JWKsHandler() gin.HandlerFunc {
var data map[string]string
json.Unmarshal([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJWK)), &data)
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{
"keys": []map[string]string{
data,

View File

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

View File

@ -10,6 +10,7 @@ import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/envstore"
"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")
}
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{}
byteData, err := json.Marshal(params)
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 {
if value != nil {
fieldType := reflect.TypeOf(value).String()
@ -117,8 +177,20 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
// Update local store
envstore.EnvInMemoryStoreObj.UpdateEnvStore(updatedData)
sessionstore.InitSession()
oauth.InitOAuth()
jwk, err := crypto.GenerateJWKBasedOnEnv()
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
env, err := db.Provider.GetEnv()

View File

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

View File

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