authorizer/server/resolvers/update_env.go

277 lines
8.1 KiB
Go
Raw Normal View History

2021-12-31 11:33:37 +00:00
package resolvers
import (
"context"
"encoding/json"
"errors"
2021-12-31 11:33:37 +00:00
"fmt"
"reflect"
2022-05-31 07:41:54 +00:00
"strings"
2021-12-31 11:33:37 +00:00
2022-05-24 07:12:29 +00:00
log "github.com/sirupsen/logrus"
2021-12-31 11:33:37 +00:00
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie"
2022-02-26 15:06:22 +00:00
"github.com/authorizerdev/authorizer/server/crypto"
2021-12-31 11:33:37 +00:00
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/graph/model"
2022-05-30 03:49:55 +00:00
"github.com/authorizerdev/authorizer/server/memorystore"
2022-01-31 06:05:24 +00:00
"github.com/authorizerdev/authorizer/server/oauth"
"github.com/authorizerdev/authorizer/server/token"
2021-12-31 11:33:37 +00:00
"github.com/authorizerdev/authorizer/server/utils"
)
2022-01-17 07:42:46 +00:00
// UpdateEnvResolver is a resolver for update config mutation
2022-01-17 06:02:13 +00:00
// This is admin only mutation
2022-01-17 07:42:46 +00:00
func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error) {
2021-12-31 11:33:37 +00:00
var res *model.Response
2022-05-24 07:12:29 +00:00
gc, err := utils.GinContextFromContext(ctx)
2021-12-31 11:33:37 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to get GinContext: ", err)
2021-12-31 11:33:37 +00:00
return res, err
}
if !token.IsSuperAdmin(gc) {
2022-05-25 07:00:22 +00:00
log.Debug("Not logged in as super admin")
2021-12-31 11:33:37 +00:00
return res, fmt.Errorf("unauthorized")
}
2022-05-30 03:49:55 +00:00
updatedData, err := memorystore.Provider.GetEnvStore()
if err != nil {
log.Debug("Failed to get env store: ", err)
return res, err
}
2022-02-26 15:06:22 +00:00
isJWTUpdated := false
2022-05-30 03:49:55 +00:00
algo := updatedData[constants.EnvKeyJwtType].(string)
2022-02-26 15:06:22 +00:00
if params.JwtType != nil {
algo = *params.JwtType
if !crypto.IsHMACA(algo) && !crypto.IsECDSA(algo) && !crypto.IsRSA(algo) {
2022-05-25 07:00:22 +00:00
log.Debug("Invalid JWT type: ", algo)
2022-02-26 15:06:22 +00:00
return res, fmt.Errorf("invalid jwt type")
}
2022-05-30 03:49:55 +00:00
updatedData[constants.EnvKeyJwtType] = algo
2022-02-26 15:06:22 +00:00
isJWTUpdated = true
}
if params.JwtSecret != nil || params.JwtPublicKey != nil || params.JwtPrivateKey != nil {
isJWTUpdated = true
}
if isJWTUpdated {
2022-03-24 16:49:30 +00:00
// use to reset when type is changed from rsa, edsa -> hmac or vice a versa
defaultSecret := ""
defaultPublicKey := ""
defaultPrivateKey := ""
2022-02-26 15:06:22 +00:00
// check if jwt secret is provided
if crypto.IsHMACA(algo) {
if params.JwtSecret == nil {
2022-05-24 07:12:29 +00:00
log.Debug("JWT secret is required for HMAC")
2022-02-26 15:06:22 +00:00
return res, fmt.Errorf("jwt secret is required for HMAC algorithm")
}
2022-03-24 16:49:30 +00:00
// reset public key and private key
params.JwtPrivateKey = &defaultPrivateKey
params.JwtPublicKey = &defaultPublicKey
2022-02-26 15:06:22 +00:00
}
if crypto.IsRSA(algo) {
if params.JwtPrivateKey == nil || params.JwtPublicKey == nil {
2022-05-25 07:00:22 +00:00
log.Debug("JWT private key and public key are required for RSA: ", *params.JwtPrivateKey, *params.JwtPublicKey)
2022-02-26 15:06:22 +00:00
return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm")
}
2022-03-24 16:49:30 +00:00
// reset the jwt secret
params.JwtSecret = &defaultSecret
2022-02-26 15:06:22 +00:00
_, err = crypto.ParseRsaPrivateKeyFromPemStr(*params.JwtPrivateKey)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Invalid JWT private key: ", err)
2022-02-26 15:06:22 +00:00
return res, err
}
_, err := crypto.ParseRsaPublicKeyFromPemStr(*params.JwtPublicKey)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Invalid JWT public key: ", err)
2022-02-26 15:06:22 +00:00
return res, err
}
}
if crypto.IsECDSA(algo) {
if params.JwtPrivateKey == nil || params.JwtPublicKey == nil {
2022-05-25 07:00:22 +00:00
log.Debug("JWT private key and public key are required for ECDSA: ", *params.JwtPrivateKey, *params.JwtPublicKey)
2022-02-26 15:06:22 +00:00
return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm")
}
2022-03-24 16:49:30 +00:00
// reset the jwt secret
params.JwtSecret = &defaultSecret
2022-02-26 15:06:22 +00:00
_, err = crypto.ParseEcdsaPrivateKeyFromPemStr(*params.JwtPrivateKey)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Invalid JWT private key: ", err)
2022-02-26 15:06:22 +00:00
return res, err
}
_, err := crypto.ParseEcdsaPublicKeyFromPemStr(*params.JwtPublicKey)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Invalid JWT public key: ", err)
2022-02-26 15:06:22 +00:00
return res, err
}
}
}
2021-12-31 11:33:37 +00:00
var data map[string]interface{}
byteData, err := json.Marshal(params)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to marshal update env input: ", err)
2021-12-31 11:33:37 +00:00
return res, fmt.Errorf("error marshalling params: %t", err)
}
err = json.Unmarshal(byteData, &data)
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to unmarshal update env input: ", err)
2021-12-31 11:33:37 +00:00
return res, fmt.Errorf("error un-marshalling params: %t", err)
}
2022-01-25 07:36:52 +00:00
// in case of admin secret change update the cookie with new hash
if params.AdminSecret != nil {
if params.OldAdminSecret == nil {
2022-05-24 07:12:29 +00:00
log.Debug("Old admin secret is required for admin secret update")
2022-01-25 07:36:52 +00:00
return res, errors.New("admin secret and old admin secret are required for secret change")
}
2022-05-30 03:49:55 +00:00
oldAdminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)
if err != nil {
log.Debug("Failed to get old admin secret: ", err)
return res, err
}
if *params.OldAdminSecret != oldAdminSecret {
2022-05-24 07:12:29 +00:00
log.Debug("Old admin secret is invalid")
2022-01-25 07:36:52 +00:00
return res, errors.New("old admin secret is not correct")
}
if len(*params.AdminSecret) < 6 {
2022-05-24 07:12:29 +00:00
log.Debug("Admin secret is too short")
2022-01-25 07:36:52 +00:00
err = fmt.Errorf("admin secret must be at least 6 characters")
return res, err
}
}
2021-12-31 11:33:37 +00:00
for key, value := range data {
if value != nil {
fieldType := reflect.TypeOf(value).String()
if fieldType == "string" {
2022-05-30 03:49:55 +00:00
updatedData[key] = value.(string)
2021-12-31 11:33:37 +00:00
}
if fieldType == "bool" {
2022-05-30 03:49:55 +00:00
updatedData[key] = value.(bool)
}
2021-12-31 11:33:37 +00:00
if fieldType == "[]interface {}" {
2022-05-31 07:41:54 +00:00
stringArr := utils.ConvertInterfaceToStringSlice(value)
updatedData[key] = strings.Join(stringArr, ",")
2021-12-31 11:33:37 +00:00
}
}
}
// handle derivative cases like disabling email verification & magic login
// in case SMTP is off but env is set to true
2022-05-30 03:49:55 +00:00
if updatedData[constants.EnvKeySmtpHost] == "" || updatedData[constants.EnvKeySmtpUsername] == "" || updatedData[constants.EnvKeySmtpPassword] == "" || updatedData[constants.EnvKeySenderEmail] == "" && updatedData[constants.EnvKeySmtpPort] == "" {
if !updatedData[constants.EnvKeyDisableEmailVerification].(bool) {
updatedData[constants.EnvKeyDisableEmailVerification] = true
2021-12-31 11:33:37 +00:00
}
2022-05-30 03:49:55 +00:00
if !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) {
updatedData[constants.EnvKeyDisableMagicLinkLogin] = true
2021-12-31 11:33:37 +00:00
}
}
// check the roles change
if len(params.Roles) > 0 {
if len(params.DefaultRoles) > 0 {
// should be subset of roles
for _, role := range params.DefaultRoles {
if !utils.StringSliceContains(params.Roles, role) {
2022-05-24 07:12:29 +00:00
log.Debug("Default roles should be subset of roles")
return res, fmt.Errorf("default role %s is not in roles", role)
}
}
}
}
if len(params.ProtectedRoles) > 0 {
for _, role := range params.ProtectedRoles {
if utils.StringSliceContains(params.Roles, role) || utils.StringSliceContains(params.DefaultRoles, role) {
2022-05-24 07:12:29 +00:00
log.Debug("Protected roles should not be in roles or default roles")
return res, fmt.Errorf("protected role %s found roles or default roles", role)
}
}
}
// Update local store
2022-05-30 03:49:55 +00:00
memorystore.Provider.UpdateEnvStore(updatedData)
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("Failed to generate JWK: ", err)
2022-02-26 15:06:22 +00:00
return res, err
}
// updating jwk
2022-05-30 03:49:55 +00:00
err = memorystore.Provider.UpdateEnvVariable(constants.EnvKeyJWK, jwk)
if err != nil {
log.Debug("Failed to update JWK: ", err)
return res, err
}
2022-05-27 17:50:38 +00:00
// TODO check how to update session store based on env change.
// err = sessionstore.InitSession()
// if err != nil {
// log.Debug("Failed to init session store: ", err)
// return res, err
// }
2022-02-26 15:06:22 +00:00
err = oauth.InitOAuth()
if err != nil {
return res, err
}
2021-12-31 11:33:37 +00:00
// Fetch the current db store and update it
2022-01-21 08:04:04 +00:00
env, err := db.Provider.GetEnv()
2021-12-31 11:33:37 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to get env: ", err)
2021-12-31 11:33:37 +00:00
return res, err
}
if params.AdminSecret != nil {
2022-05-30 03:49:55 +00:00
adminSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)
if err != nil {
log.Debug("Failed to get admin secret: ", err)
return res, err
}
hashedKey, err := crypto.EncryptPassword(adminSecret)
2021-12-31 11:33:37 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to encrypt admin secret: ", err)
2021-12-31 11:33:37 +00:00
return res, err
}
cookie.SetAdminCookie(gc, hashedKey)
2021-12-31 11:33:37 +00:00
}
2022-02-28 15:56:49 +00:00
encryptedConfig, err := crypto.EncryptEnvData(updatedData)
2022-01-25 07:36:52 +00:00
if err != nil {
2022-05-25 07:00:22 +00:00
log.Debug("Failed to encrypt env data: ", err)
2022-01-25 07:36:52 +00:00
return res, err
}
env.EnvData = encryptedConfig
2022-01-21 08:04:04 +00:00
_, err = db.Provider.UpdateEnv(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 env: ", err)
2021-12-31 11:33:37 +00:00
return res, err
}
res = &model.Response{
Message: "configurations updated successfully",
}
return res, nil
}