From ae34fc7c2b70d02505184ca8640af2f5a60bb817 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Fri, 1 Jul 2022 22:02:34 +0530 Subject: [PATCH] fix: update_env resolver --- .../memorystore/providers/inmemory/store.go | 15 ++--- .../inmemory/stores/session_store.go | 16 +++++ server/memorystore/providers/providers.go | 2 + server/memorystore/providers/redis/store.go | 26 ++++++++ server/resolvers/update_env.go | 65 +++++++++++++++++-- 5 files changed, 109 insertions(+), 15 deletions(-) diff --git a/server/memorystore/providers/inmemory/store.go b/server/memorystore/providers/inmemory/store.go index 160c474..ebd0c06 100644 --- a/server/memorystore/providers/inmemory/store.go +++ b/server/memorystore/providers/inmemory/store.go @@ -35,10 +35,7 @@ func (c *provider) DeleteAllUserSessions(userId string) error { constants.AuthRecipeMethodGoogle, constants.AuthRecipeMethodLinkedIn, } - if os.Getenv("ENV") != constants.TestEnv { - c.mutex.Lock() - defer c.mutex.Unlock() - } + for _, namespace := range namespaces { c.sessionStore.RemoveAll(namespace + ":" + userId) } @@ -47,14 +44,16 @@ func (c *provider) DeleteAllUserSessions(userId string) error { // DeleteUserSession deletes the user session from the in-memory store. func (c *provider) DeleteUserSession(userId, sessionToken string) error { - if os.Getenv("ENV") != constants.TestEnv { - c.mutex.Lock() - defer c.mutex.Unlock() - } c.sessionStore.Remove(userId, sessionToken) return nil } +// DeleteSessionForNamespace to delete session for a given namespace example google,github +func (c *provider) DeleteSessionForNamespace(namespace string) error { + c.sessionStore.RemoveByNamespace(namespace) + return nil +} + // SetState sets the state in the in-memory store. func (c *provider) SetState(key, state string) error { if os.Getenv("ENV") != constants.TestEnv { diff --git a/server/memorystore/providers/inmemory/stores/session_store.go b/server/memorystore/providers/inmemory/stores/session_store.go index c75a3d7..d702fa0 100644 --- a/server/memorystore/providers/inmemory/stores/session_store.go +++ b/server/memorystore/providers/inmemory/stores/session_store.go @@ -2,6 +2,7 @@ package stores import ( "os" + "strings" "sync" "github.com/authorizerdev/authorizer/server/constants" @@ -65,3 +66,18 @@ func (s *SessionStore) GetAll(key string) map[string]string { } return s.store[key] } + +// RemoveByNamespace to delete session for a given namespace example google,github +func (s *SessionStore) RemoveByNamespace(namespace string) error { + if os.Getenv("ENV") != constants.TestEnv { + s.mutex.Lock() + defer s.mutex.Unlock() + } + + for key := range s.store { + if strings.Contains(key, namespace+":") { + delete(s.store, key) + } + } + return nil +} diff --git a/server/memorystore/providers/providers.go b/server/memorystore/providers/providers.go index f3b2471..4953edb 100644 --- a/server/memorystore/providers/providers.go +++ b/server/memorystore/providers/providers.go @@ -12,6 +12,8 @@ type Provider interface { DeleteUserSession(userId, key string) error // DeleteAllSessions deletes all the sessions from the session store DeleteAllUserSessions(userId string) error + // DeleteSessionForNamespace deletes the session for a given namespace + DeleteSessionForNamespace(namespace string) error // SetState sets the login state (key, value form) in the session store SetState(key, state string) error diff --git a/server/memorystore/providers/redis/store.go b/server/memorystore/providers/redis/store.go index f7fc478..36b4b0c 100644 --- a/server/memorystore/providers/redis/store.go +++ b/server/memorystore/providers/redis/store.go @@ -82,6 +82,32 @@ func (c *provider) DeleteAllUserSessions(userID string) error { return nil } +// DeleteSessionForNamespace to delete session for a given namespace example google,github +func (c *provider) DeleteSessionForNamespace(namespace string) error { + var cursor uint64 + for { + keys := []string{} + keys, cursor, err := c.store.Scan(c.ctx, cursor, namespace+":*", 0).Result() + if err != nil { + log.Debugf("Error scanning keys for %s namespace: %s", namespace, err.Error()) + return err + } + + for _, key := range keys { + err := c.store.Del(c.ctx, key).Err() + if err != nil { + log.Debugf("Error deleting sessions for %s namespace: %s", namespace, err.Error()) + return err + } + } + if cursor == 0 { // no more keys + break + } + } + + return nil +} + // SetState sets the state in redis store. func (c *provider) SetState(key, value string) error { err := c.store.Set(c.ctx, stateStorePrefix+key, value, 0).Err() diff --git a/server/resolvers/update_env.go b/server/resolvers/update_env.go index d7023a0..41fe5fa 100644 --- a/server/resolvers/update_env.go +++ b/server/resolvers/update_env.go @@ -21,6 +21,54 @@ import ( "github.com/authorizerdev/authorizer/server/utils" ) +// check if login methods have been disabled +// remove the session tokens for those methods +func clearSessionIfRequired(currentData, updatedData map[string]interface{}) { + isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool) + isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool) + isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != "" + isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != "" + isCurrentGoogleLoginEnabled := currentData[constants.EnvKeyGoogleClientID] != nil && currentData[constants.EnvKeyGoogleClientSecret] != nil && currentData[constants.EnvKeyGoogleClientID].(string) != "" && currentData[constants.EnvKeyGoogleClientSecret].(string) != "" + isCurrentGithubLoginEnabled := currentData[constants.EnvKeyGithubClientID] != nil && currentData[constants.EnvKeyGithubClientSecret] != nil && currentData[constants.EnvKeyGithubClientID].(string) != "" && currentData[constants.EnvKeyGithubClientSecret].(string) != "" + isCurrentLinkedInLoginEnabled := currentData[constants.EnvKeyLinkedInClientID] != nil && currentData[constants.EnvKeyLinkedInClientSecret] != nil && currentData[constants.EnvKeyLinkedInClientID].(string) != "" && currentData[constants.EnvKeyLinkedInClientSecret].(string) != "" + + isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool) + isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) + isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != "" + isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != "" + isUpdatedGoogleLoginEnabled := updatedData[constants.EnvKeyGoogleClientID] != nil && updatedData[constants.EnvKeyGoogleClientSecret] != nil && updatedData[constants.EnvKeyGoogleClientID].(string) != "" && updatedData[constants.EnvKeyGoogleClientSecret].(string) != "" + isUpdatedGithubLoginEnabled := updatedData[constants.EnvKeyGithubClientID] != nil && updatedData[constants.EnvKeyGithubClientSecret] != nil && updatedData[constants.EnvKeyGithubClientID].(string) != "" && updatedData[constants.EnvKeyGithubClientSecret].(string) != "" + isUpdatedLinkedInLoginEnabled := updatedData[constants.EnvKeyLinkedInClientID] != nil && updatedData[constants.EnvKeyLinkedInClientSecret] != nil && updatedData[constants.EnvKeyLinkedInClientID].(string) != "" && updatedData[constants.EnvKeyLinkedInClientSecret].(string) != "" + + if isCurrentBasicAuthEnabled && !isUpdatedBasicAuthEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth) + } + + if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin) + } + + if isCurrentAppleLoginEnabled && !isUpdatedAppleLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodApple) + } + + if isCurrentFacebookLoginEnabled && !isUpdatedFacebookLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodFacebook) + } + + if isCurrentGoogleLoginEnabled && !isUpdatedGoogleLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodGoogle) + } + + if isCurrentGithubLoginEnabled && !isUpdatedGithubLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodGithub) + } + + if isCurrentLinkedInLoginEnabled && !isUpdatedLinkedInLoginEnabled { + memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodLinkedIn) + } +} + // UpdateEnvResolver is a resolver for update config mutation // This is admin only mutation func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error) { @@ -37,12 +85,19 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model return res, fmt.Errorf("unauthorized") } - updatedData, err := memorystore.Provider.GetEnvStore() + currentData, err := memorystore.Provider.GetEnvStore() if err != nil { log.Debug("Failed to get env store: ", err) return res, err } + // clone currentData in new var + // that will be updated based on the req + updatedData := make(map[string]interface{}) + for key, val := range currentData { + updatedData[key] = val + } + isJWTUpdated := false algo := updatedData[constants.EnvKeyJwtType].(string) if params.JwtType != nil { @@ -210,6 +265,8 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model } } + go clearSessionIfRequired(currentData, updatedData) + // Update local store memorystore.Provider.UpdateEnvStore(updatedData) jwk, err := crypto.GenerateJWKBasedOnEnv() @@ -224,12 +281,6 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model return res, err } - // 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 - // } err = oauth.InitOAuth() if err != nil { return res, err