authorizer/server/env/persist_env.go

269 lines
7.8 KiB
Go
Raw Normal View History

2021-12-31 08:22:10 +00:00
package env
import (
2022-07-10 16:19:33 +00:00
"context"
2021-12-31 08:22:10 +00:00
"encoding/json"
"os"
2022-05-31 07:41:54 +00:00
"reflect"
"strconv"
2021-12-31 08:22:10 +00:00
"strings"
2022-02-26 15:06:22 +00:00
"github.com/google/uuid"
2022-05-13 01:58:31 +00:00
log "github.com/sirupsen/logrus"
2022-02-26 15:06:22 +00:00
2021-12-31 08:22:10 +00:00
"github.com/authorizerdev/authorizer/server/constants"
2022-02-26 15:06:22 +00:00
"github.com/authorizerdev/authorizer/server/crypto"
2021-12-31 08:22:10 +00:00
"github.com/authorizerdev/authorizer/server/db"
2022-01-21 08:04:04 +00:00
"github.com/authorizerdev/authorizer/server/db/models"
2022-05-29 11:52:46 +00:00
"github.com/authorizerdev/authorizer/server/memorystore"
2022-05-31 07:41:54 +00:00
"github.com/authorizerdev/authorizer/server/utils"
2021-12-31 08:22:10 +00:00
)
2022-05-31 07:41:54 +00:00
func fixBackwardCompatibility(data map[string]interface{}) (bool, map[string]interface{}) {
result := data
// check if env data is stored in older format
hasOlderFormat := false
if _, ok := result["bool_env"]; ok {
for key, value := range result["bool_env"].(map[string]interface{}) {
result[key] = value
}
hasOlderFormat = true
delete(result, "bool_env")
}
if _, ok := result["string_env"]; ok {
for key, value := range result["string_env"].(map[string]interface{}) {
result[key] = value
}
hasOlderFormat = true
delete(result, "string_env")
}
if _, ok := result["slice_env"]; ok {
for key, value := range result["slice_env"].(map[string]interface{}) {
typeOfValue := reflect.TypeOf(value)
if strings.Contains(typeOfValue.String(), "[]string") {
result[key] = strings.Join(value.([]string), ",")
}
if strings.Contains(typeOfValue.String(), "[]interface") {
result[key] = strings.Join(utils.ConvertInterfaceToStringSlice(value), ",")
}
}
hasOlderFormat = true
delete(result, "slice_env")
}
return hasOlderFormat, result
}
2022-02-26 04:14:55 +00:00
// GetEnvData returns the env data from database
2022-05-29 11:52:46 +00:00
func GetEnvData() (map[string]interface{}, error) {
var result map[string]interface{}
2022-07-10 16:19:33 +00:00
ctx := context.Background()
env, err := db.Provider.GetEnv(ctx)
2022-02-26 04:14:55 +00:00
// config not found in db
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while getting env data from db: ", err)
2022-02-26 04:14:55 +00:00
return result, err
}
encryptionKey := env.Hash
2022-02-28 15:56:49 +00:00
decryptedEncryptionKey, err := crypto.DecryptB64(encryptionKey)
2022-02-26 04:14:55 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while decrypting encryption key: ", err)
2022-02-26 04:14:55 +00:00
return result, err
}
2022-05-29 11:52:46 +00:00
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
2022-02-26 04:14:55 +00:00
2022-03-07 10:05:33 +00:00
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while decrypting env data from B64: ", err)
2022-03-07 10:05:33 +00:00
return result, err
}
decryptedConfigs, err := crypto.DecryptAESEnv([]byte(b64DecryptedConfig))
2022-02-26 04:14:55 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while decrypting env data from AES: ", err)
2022-02-26 04:14:55 +00:00
return result, err
}
2022-03-07 09:59:37 +00:00
err = json.Unmarshal(decryptedConfigs, &result)
2022-02-26 04:14:55 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while unmarshalling env data: ", err)
2022-02-26 04:14:55 +00:00
return result, err
}
2022-05-31 07:41:54 +00:00
hasOlderFormat, result := fixBackwardCompatibility(result)
2022-05-31 02:44:03 +00:00
if hasOlderFormat {
2022-05-31 07:41:54 +00:00
err = memorystore.Provider.UpdateEnvStore(result)
2022-05-31 02:44:03 +00:00
if err != nil {
2022-05-31 07:41:54 +00:00
log.Debug("Error while updating env store: ", err)
2022-05-31 02:44:03 +00:00
return result, err
}
2022-05-31 07:41:54 +00:00
2022-05-31 02:44:03 +00:00
}
2022-02-26 04:14:55 +00:00
return result, err
}
2022-01-17 06:02:13 +00:00
// PersistEnv persists the environment variables to the database
2021-12-31 08:22:10 +00:00
func PersistEnv() error {
2022-07-10 16:19:33 +00:00
ctx := context.Background()
env, err := db.Provider.GetEnv(ctx)
2021-12-31 08:22:10 +00:00
// config not found in db
if err != nil || env.EnvData == "" {
2021-12-31 08:22:10 +00:00
// AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid
hash := uuid.New().String()[:36-4]
2022-05-31 07:41:54 +00:00
err := memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, hash)
if err != nil {
log.Debug("Error while updating encryption env variable: ", err)
return err
}
2022-02-28 15:56:49 +00:00
encodedHash := crypto.EncryptB64(hash)
2021-12-31 08:22:10 +00:00
2022-05-29 11:52:46 +00:00
res, err := memorystore.Provider.GetEnvStore()
if err != nil {
log.Debug("Error while getting env store: ", err)
return err
}
encryptedConfig, err := crypto.EncryptEnvData(res)
2021-12-31 08:22:10 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while encrypting env data: ", err)
2021-12-31 08:22:10 +00:00
return err
}
2022-01-21 08:04:04 +00:00
env = models.Env{
Hash: encodedHash,
EnvData: encryptedConfig,
2021-12-31 08:22:10 +00:00
}
2022-07-10 16:19:33 +00:00
env, err = db.Provider.AddEnv(ctx, env)
2022-02-26 04:14:55 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while persisting env data to db: ", err)
2022-02-26 04:14:55 +00:00
return err
}
2021-12-31 08:22:10 +00:00
} else {
// decrypt the config data from db
// decryption can be done using the hash stored in db
encryptionKey := env.Hash
2022-02-28 15:56:49 +00:00
decryptedEncryptionKey, err := crypto.DecryptB64(encryptionKey)
2021-12-31 08:22:10 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while decrypting encryption key: ", err)
2021-12-31 08:22:10 +00:00
return err
}
2022-01-17 06:02:13 +00:00
2022-05-29 11:52:46 +00:00
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
2022-01-29 11:32:44 +00:00
2022-03-07 10:03:39 +00:00
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while decrypting env data from B64: ", err)
2022-03-07 10:03:39 +00:00
return err
}
decryptedConfigs, err := crypto.DecryptAESEnv([]byte(b64DecryptedConfig))
2021-12-31 08:22:10 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while decrypting env data from AES: ", err)
2021-12-31 08:22:10 +00:00
return err
}
// temp store variable
2022-05-29 11:52:46 +00:00
storeData := map[string]interface{}{}
2021-12-31 08:22:10 +00:00
2022-03-07 09:59:37 +00:00
err = json.Unmarshal(decryptedConfigs, &storeData)
2021-12-31 08:22:10 +00:00
if err != nil {
log.Debug("Error while un-marshalling env data: ", err)
2021-12-31 08:22:10 +00:00
return err
}
2022-05-31 07:41:54 +00:00
hasOlderFormat, result := fixBackwardCompatibility(storeData)
if hasOlderFormat {
err = memorystore.Provider.UpdateEnvStore(result)
if err != nil {
log.Debug("Error while updating env store: ", err)
return err
}
}
2021-12-31 08:22:10 +00:00
// if env is changed via env file or OS env
// give that higher preference and update db, but we don't recommend it
hasChanged := false
2022-05-29 11:52:46 +00:00
for key, value := range storeData {
2022-02-26 15:06:22 +00:00
// don't override unexposed envs
2022-05-29 11:52:46 +00:00
// 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
2022-03-07 13:19:18 +00:00
if key != constants.EnvKeyEncryptionKey {
envValue := strings.TrimSpace(os.Getenv(key))
if envValue != "" {
2022-05-29 11:52:46 +00:00
switch key {
2022-08-03 17:50:23 +00:00
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication:
2022-05-29 11:52:46 +00:00
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
if value.(bool) != envValueBool {
storeData[key] = envValueBool
hasChanged = true
}
}
default:
2022-05-31 02:44:03 +00:00
if value != nil && value.(string) != envValue {
2022-05-29 11:52:46 +00:00
storeData[key] = envValue
hasChanged = true
}
2021-12-31 08:22:10 +00:00
}
}
}
}
2021-12-31 08:22:10 +00:00
// handle derivative cases like disabling email verification & magic login
// in case SMTP is off but env is set to true
2022-05-29 11:52:46 +00:00
if storeData[constants.EnvKeySmtpHost] == "" || storeData[constants.EnvKeySmtpUsername] == "" || storeData[constants.EnvKeySmtpPassword] == "" || storeData[constants.EnvKeySenderEmail] == "" && storeData[constants.EnvKeySmtpPort] == "" {
2022-07-29 14:19:50 +00:00
storeData[constants.EnvKeyIsEmailServiceEnabled] = false
2022-05-29 11:52:46 +00:00
if !storeData[constants.EnvKeyDisableEmailVerification].(bool) {
storeData[constants.EnvKeyDisableEmailVerification] = true
2021-12-31 08:22:10 +00:00
hasChanged = true
}
2022-05-29 11:52:46 +00:00
if !storeData[constants.EnvKeyDisableMagicLinkLogin].(bool) {
storeData[constants.EnvKeyDisableMagicLinkLogin] = true
2021-12-31 08:22:10 +00:00
hasChanged = true
}
}
2022-03-25 14:59:00 +00:00
2022-05-29 11:52:46 +00:00
err = memorystore.Provider.UpdateEnvStore(storeData)
if err != nil {
log.Debug("Error while updating env store: ", err)
return err
}
2022-02-26 15:06:22 +00:00
jwk, err := crypto.GenerateJWKBasedOnEnv()
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while generating JWK: ", err)
2022-02-26 15:06:22 +00:00
return err
}
// updating jwk
2022-05-29 11:52:46 +00:00
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJWK, jwk)
2022-02-26 04:14:55 +00:00
2021-12-31 08:22:10 +00:00
if hasChanged {
2022-02-28 15:56:49 +00:00
encryptedConfig, err := crypto.EncryptEnvData(storeData)
2021-12-31 11:33:37 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Error while encrypting env data: ", err)
2021-12-31 11:33:37 +00:00
return err
}
2021-12-31 08:22:10 +00:00
env.EnvData = encryptedConfig
2022-07-10 16:19:33 +00:00
_, err = db.Provider.UpdateEnv(ctx, env)
2021-12-31 11:33:37 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to Update Config: ", err)
2021-12-31 11:33:37 +00:00
return err
}
2021-12-31 08:22:10 +00:00
}
}
return nil
}