From d7bb10fd212d065cd6c109465f2ace724eb8d6cc Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Tue, 24 May 2022 12:42:29 +0530 Subject: [PATCH] feat: add loggging to all resolvers --- server/oauth/oauth.go | 5 ++-- server/resolvers/admin_login.go | 6 +++- server/resolvers/admin_logout.go | 6 +++- server/resolvers/admin_session.go | 7 ++++- server/resolvers/admin_signup.go | 14 ++++++++- server/resolvers/delete_user.go | 12 ++++++-- server/resolvers/enable_access.go | 15 ++++++++-- server/resolvers/env.go | 6 +++- server/resolvers/forgot_password.go | 13 ++++++-- server/resolvers/generate_jwt_keys.go | 7 +++++ server/resolvers/invite_members.go | 19 ++++++++---- server/resolvers/login.go | 21 ++++++++++--- server/resolvers/logout.go | 8 ++++- server/resolvers/magic_link_login.go | 21 +++++++++++-- server/resolvers/profile.go | 13 +++++++- server/resolvers/resend_verify_email.go | 18 +++++++++--- server/resolvers/reset_password.go | 29 ++++++++++++++++-- server/resolvers/revoke_access.go | 14 +++++++-- server/resolvers/session.go | 19 ++++++++---- server/resolvers/signup.go | 30 ++++++++++++++++--- server/resolvers/update_env.go | 29 ++++++++++++++++-- server/resolvers/update_profile.go | 36 ++++++++++++++++++----- server/resolvers/update_user.go | 33 +++++++++++++++++---- server/resolvers/users.go | 5 ++++ server/resolvers/validate_jwt_token.go | 9 +++++- server/resolvers/verification_requests.go | 5 ++++ server/resolvers/verify_email.go | 18 ++++++++++-- 27 files changed, 350 insertions(+), 68 deletions(-) diff --git a/server/oauth/oauth.go b/server/oauth/oauth.go index 7e7c2d7..3618a9a 100644 --- a/server/oauth/oauth.go +++ b/server/oauth/oauth.go @@ -3,12 +3,13 @@ package oauth import ( "context" - "github.com/authorizerdev/authorizer/server/constants" - "github.com/authorizerdev/authorizer/server/envstore" "github.com/coreos/go-oidc/v3/oidc" "golang.org/x/oauth2" facebookOAuth2 "golang.org/x/oauth2/facebook" githubOAuth2 "golang.org/x/oauth2/github" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/envstore" ) // OAuthProviders is a struct that contains reference all the OAuth providers diff --git a/server/resolvers/admin_login.go b/server/resolvers/admin_login.go index 3e28b3f..d9875ed 100644 --- a/server/resolvers/admin_login.go +++ b/server/resolvers/admin_login.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/crypto" @@ -14,15 +16,17 @@ import ( // AdminLoginResolver is a resolver for admin login mutation func AdminLoginResolver(ctx context.Context, params model.AdminLoginInput) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } adminSecret := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) if params.AdminSecret != adminSecret { + log.Debug("Admin secret is not correct") return res, fmt.Errorf(`invalid admin secret`) } diff --git a/server/resolvers/admin_logout.go b/server/resolvers/admin_logout.go index 370c414..08c9a9a 100644 --- a/server/resolvers/admin_logout.go +++ b/server/resolvers/admin_logout.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/token" @@ -12,14 +14,16 @@ import ( // AdminLogoutResolver is a resolver for admin logout mutation func AdminLogoutResolver(ctx context.Context) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if !token.IsSuperAdmin(gc) { + log.Debug("Admin is not logged in") return res, fmt.Errorf("unauthorized") } diff --git a/server/resolvers/admin_session.go b/server/resolvers/admin_session.go index 9809835..69ba27e 100644 --- a/server/resolvers/admin_session.go +++ b/server/resolvers/admin_session.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/crypto" @@ -15,19 +17,22 @@ import ( // AdminSessionResolver is a resolver for admin session query func AdminSessionResolver(ctx context.Context) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return res, fmt.Errorf("unauthorized") } hashedKey, err := crypto.EncryptPassword(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)) if err != nil { + log.Debug("Failed to encrypt key:", err) return res, err } cookie.SetAdminCookie(gc, hashedKey) diff --git a/server/resolvers/admin_signup.go b/server/resolvers/admin_signup.go index bb2f1eb..390e290 100644 --- a/server/resolvers/admin_signup.go +++ b/server/resolvers/admin_signup.go @@ -6,6 +6,8 @@ import ( "fmt" "strings" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/crypto" @@ -17,19 +19,22 @@ import ( // AdminSignupResolver is a resolver for admin signup mutation func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext:", err) return res, err } if strings.TrimSpace(params.AdminSecret) == "" { + log.Debug("Admin secret is empty") err = fmt.Errorf("please select secure admin secret") return res, err } if len(params.AdminSecret) < 6 { + log.Debug("Admin secret is too short") err = fmt.Errorf("admin secret must be at least 6 characters") return res, err } @@ -37,6 +42,7 @@ func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*m adminSecret := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) if adminSecret != "" { + log.Debug("Admin secret is already set") err = fmt.Errorf("admin sign up already completed") return res, err } @@ -47,30 +53,36 @@ func AdminSignupResolver(ctx context.Context, params model.AdminSignupInput) (*m jsonBytes, err := json.Marshal(envstore.EnvStoreObj.GetEnvStoreClone()) if err != nil { + log.Debug("Failed to marshal envstore:", err) return res, err } if err := json.Unmarshal(jsonBytes, &storeData); err != nil { + log.Debug("Failed to unmarshal envstore:", err) return res, err } env, err := db.Provider.GetEnv() if err != nil { + log.Debug("Failed to get env:", err) return res, err } envData, err := crypto.EncryptEnvData(storeData) if err != nil { + log.Debug("Failed to encrypt envstore:", err) return res, err } env.EnvData = envData if _, err := db.Provider.UpdateEnv(env); err != nil { + log.Debug("Failed to update env:", err) return res, err } hashedKey, err := crypto.EncryptPassword(params.AdminSecret) if err != nil { + log.Debug("Failed to encrypt admin session key:", err) return res, err } cookie.SetAdminCookie(gc, hashedKey) diff --git a/server/resolvers/delete_user.go b/server/resolvers/delete_user.go index c6f84ce..eae2279 100644 --- a/server/resolvers/delete_user.go +++ b/server/resolvers/delete_user.go @@ -15,18 +15,26 @@ import ( // DeleteUserResolver is a resolver for delete user mutation func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return res, fmt.Errorf("unauthorized") } + log := log.WithFields(log.Fields{ + "email": params.Email, + }) + user, err := db.Provider.GetUserByEmail(params.Email) if err != nil { + log.Debug("Failed to get user from DB:", err) return res, err } @@ -34,7 +42,7 @@ func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*mod err = db.Provider.DeleteUser(user) if err != nil { - log.Debug("Failed Deleting User:", err) + log.Debug("Failed to delete user:", err) return res, err } diff --git a/server/resolvers/enable_access.go b/server/resolvers/enable_access.go index 647cada..32c8c91 100644 --- a/server/resolvers/enable_access.go +++ b/server/resolvers/enable_access.go @@ -3,7 +3,8 @@ package resolvers import ( "context" "fmt" - "log" + + log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/graph/model" @@ -13,18 +14,26 @@ import ( // EnableAccessResolver is a resolver for enabling user access func EnableAccessResolver(ctx context.Context, params model.UpdateAccessInput) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return res, fmt.Errorf("unauthorized") } + log := log.WithFields(log.Fields{ + "user_id": params.UserID, + }) + user, err := db.Provider.GetUserByID(params.UserID) if err != nil { + log.Debug("Failed to get user from DB:", err) return res, err } @@ -32,7 +41,7 @@ func EnableAccessResolver(ctx context.Context, params model.UpdateAccessInput) ( user, err = db.Provider.UpdateUser(user) if err != nil { - log.Println("error updating user:", err) + log.Debug("Failed to update user:", err) return res, err } diff --git a/server/resolvers/env.go b/server/resolvers/env.go index b8c2d3d..7d2c415 100644 --- a/server/resolvers/env.go +++ b/server/resolvers/env.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/graph/model" @@ -14,14 +16,16 @@ import ( // EnvResolver is a resolver for config query // This is admin only query func EnvResolver(ctx context.Context) (*model.Env, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Env + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return res, fmt.Errorf("unauthorized") } diff --git a/server/resolvers/forgot_password.go b/server/resolvers/forgot_password.go index 58edb08..0388e8c 100644 --- a/server/resolvers/forgot_password.go +++ b/server/resolvers/forgot_password.go @@ -3,10 +3,11 @@ package resolvers import ( "context" "fmt" - "log" "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db/models" @@ -19,20 +20,28 @@ import ( // ForgotPasswordResolver is a resolver for forgot password mutation func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInput) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } + if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) { + log.Debug("Basic authentication is disabled.") return res, fmt.Errorf(`basic authentication is disabled for this instance`) } params.Email = strings.ToLower(params.Email) if !utils.IsValidEmail(params.Email) { + log.Debug("Invalid email address.") return res, fmt.Errorf("invalid email") } + log := log.WithFields(log.Fields{ + "email": params.Email, + }) _, err = db.Provider.GetUserByEmail(params.Email) if err != nil { return res, fmt.Errorf(`user with this email not found`) diff --git a/server/resolvers/generate_jwt_keys.go b/server/resolvers/generate_jwt_keys.go index 6c4c9e5..8280578 100644 --- a/server/resolvers/generate_jwt_keys.go +++ b/server/resolvers/generate_jwt_keys.go @@ -10,16 +10,19 @@ import ( "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" + log "github.com/sirupsen/logrus" ) // GenerateJWTKeysResolver mutation to generate new jwt keys func GenerateJWTKeysResolver(ctx context.Context, params model.GenerateJWTKeysInput) (*model.GenerateJWTKeysResponse, error) { gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return nil, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return nil, fmt.Errorf("unauthorized") } @@ -27,6 +30,7 @@ func GenerateJWTKeysResolver(ctx context.Context, params model.GenerateJWTKeysIn if crypto.IsHMACA(params.Type) { secret, _, err := crypto.NewHMACKey(params.Type, clientID) if err != nil { + log.Debug("Failed to generate new HMAC key:", err) return nil, err } return &model.GenerateJWTKeysResponse{ @@ -37,6 +41,7 @@ func GenerateJWTKeysResolver(ctx context.Context, params model.GenerateJWTKeysIn if crypto.IsRSA(params.Type) { _, privateKey, publicKey, _, err := crypto.NewRSAKey(params.Type, clientID) if err != nil { + log.Debug("Failed to generate new RSA key:", err) return nil, err } return &model.GenerateJWTKeysResponse{ @@ -48,6 +53,7 @@ func GenerateJWTKeysResolver(ctx context.Context, params model.GenerateJWTKeysIn if crypto.IsECDSA(params.Type) { _, privateKey, publicKey, _, err := crypto.NewECDSAKey(params.Type, clientID) if err != nil { + log.Debug("Failed to generate new ECDSA key:", err) return nil, err } return &model.GenerateJWTKeysResponse{ @@ -56,5 +62,6 @@ func GenerateJWTKeysResolver(ctx context.Context, params model.GenerateJWTKeysIn }, nil } + log.Debug("Invalid algorithm:", params.Type) return nil, fmt.Errorf("invalid algorithm") } diff --git a/server/resolvers/invite_members.go b/server/resolvers/invite_members.go index 1a6a0cf..315575f 100644 --- a/server/resolvers/invite_members.go +++ b/server/resolvers/invite_members.go @@ -4,10 +4,11 @@ import ( "context" "errors" "fmt" - "log" "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db/models" @@ -22,19 +23,23 @@ import ( func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) (*model.Response, error) { gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return nil, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return nil, errors.New("unauthorized") } // this feature is only allowed if email server is configured if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) { + log.Debug("Email server is not configured.") return nil, errors.New("email sending is disabled") } if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) && envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableMagicLinkLogin) { + log.Debug("Basic authentication and Magic link login is disabled.") return nil, errors.New("either basic authentication or magic link login is required") } @@ -47,6 +52,7 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) } if len(emails) == 0 { + log.Debug("No valid email addresses.") return nil, errors.New("no valid emails found") } @@ -56,14 +62,15 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) for _, email := range emails { _, err := db.Provider.GetUserByEmail(email) if err != nil { - log.Printf("%s user not found. inviting user.", email) + log.Info("User with this email not found, so inviting...") newEmails = append(newEmails, email) } else { - log.Println("%s user already exists. skipping.", email) + log.Info("User with this email already exists, so not inviting...") } } if len(newEmails) == 0 { + log.Debug("No new emails found.") return nil, errors.New("all emails already exist") } @@ -90,7 +97,7 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) verificationToken, err := token.CreateVerificationToken(email, constants.VerificationTypeForgotPassword, hostname, nonceHash, redirectURL) if err != nil { - log.Println(`error generating token`, err) + log.Debug("Failed to create verification token.", err) } verificationRequest := models.VerificationRequest{ @@ -116,13 +123,13 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput) user, err = db.Provider.AddUser(user) if err != nil { - log.Printf("error inviting user: %s, err: %v", email, err) + log.Debug("Error adding user: %s, err: %v", email, err) return nil, err } _, err = db.Provider.AddVerificationRequest(verificationRequest) if err != nil { - log.Printf("error inviting user: %s, err: %v", email, err) + log.Debug("Error adding verification request: %s, err: %v", email, err) return nil, err } diff --git a/server/resolvers/login.go b/server/resolvers/login.go index d27cf90..811afc7 100644 --- a/server/resolvers/login.go +++ b/server/resolvers/login.go @@ -3,10 +3,12 @@ package resolvers import ( "context" "fmt" - "log" "strings" "time" + log "github.com/sirupsen/logrus" + "golang.org/x/crypto/bcrypt" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/db" @@ -16,49 +18,59 @@ import ( "github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" - "golang.org/x/crypto/bcrypt" ) // LoginResolver is a resolver for login mutation func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.AuthResponse + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) { + log.Debug("Basic authentication is disabled.") return res, fmt.Errorf(`basic authentication is disabled for this instance`) } + log := log.WithFields(log.Fields{ + "email": params.Email, + }) params.Email = strings.ToLower(params.Email) user, err := db.Provider.GetUserByEmail(params.Email) if err != nil { + log.Debug("Failed to get user by email", err) return res, fmt.Errorf(`user with this email not found`) } if user.RevokedTimestamp != nil { + log.Debug("User access is revoked") return res, fmt.Errorf(`user access has been revoked`) } if !strings.Contains(user.SignupMethods, constants.SignupMethodBasicAuth) { + log.Debug("User signup method is not basic auth") return res, fmt.Errorf(`user has not signed up email & password`) } if user.EmailVerifiedAt == nil { + log.Debug("User email is not verified") return res, fmt.Errorf(`email not verified`) } err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password)) if err != nil { - log.Println("compare password error:", err) + log.Debug("Failed to compare password", err) return res, fmt.Errorf(`invalid password`) } roles := envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyDefaultRoles) currentRoles := strings.Split(user.Roles, ",") if len(params.Roles) > 0 { if !utils.IsValidRoles(params.Roles, currentRoles) { + log.Debug("Invalid roles") return res, fmt.Errorf(`invalid roles`) } @@ -72,6 +84,7 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes authToken, err := token.CreateAuthToken(gc, user, roles, scope) if err != nil { + log.Debug("Failed to create auth token", err) return res, err } diff --git a/server/resolvers/logout.go b/server/resolvers/logout.go index d2dfbc2..dfbaf1d 100644 --- a/server/resolvers/logout.go +++ b/server/resolvers/logout.go @@ -3,6 +3,8 @@ package resolvers import ( "context" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/crypto" "github.com/authorizerdev/authorizer/server/graph/model" @@ -12,20 +14,24 @@ import ( // LogoutResolver is a resolver for logout mutation func LogoutResolver(ctx context.Context) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } // get fingerprint hash fingerprintHash, err := cookie.GetSession(gc) if err != nil { + log.Debug("Failed to get fingerprint hash:", err) return res, err } decryptedFingerPrint, err := crypto.DecryptAES(fingerprintHash) if err != nil { + log.Debug("Failed to decrypt fingerprint hash:", err) return res, err } diff --git a/server/resolvers/magic_link_login.go b/server/resolvers/magic_link_login.go index cba2c43..13093b2 100644 --- a/server/resolvers/magic_link_login.go +++ b/server/resolvers/magic_link_login.go @@ -3,10 +3,11 @@ package resolvers import ( "context" "fmt" - "log" "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db/models" @@ -20,21 +21,29 @@ import ( // MagicLinkLoginResolver is a resolver for magic link login mutation func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) { var res *model.Response + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableMagicLinkLogin) { + log.Debug("Magic link login is disabled.") return res, fmt.Errorf(`magic link login is disabled for this instance`) } params.Email = strings.ToLower(params.Email) if !utils.IsValidEmail(params.Email) { + log.Debug("Invalid email") return res, fmt.Errorf(`invalid email address`) } + log := log.WithFields(log.Fields{ + "email": params.Email, + }) + inputRoles := []string{} user := models.User{ @@ -45,6 +54,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu existingUser, err := db.Provider.GetUserByEmail(params.Email) if err != nil { if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) { + log.Debug("Signup is disabled.") return res, fmt.Errorf(`signup is disabled for this instance`) } @@ -53,6 +63,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu if len(params.Roles) > 0 { // check if roles exists if !utils.IsValidRoles(params.Roles, envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyRoles)) { + log.Debug("Invalid roles") return res, fmt.Errorf(`invalid roles`) } else { inputRoles = params.Roles @@ -71,6 +82,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu // Need to modify roles in this case if user.RevokedTimestamp != nil { + log.Debug("User access is revoked") return res, fmt.Errorf(`user access has been revoked`) } @@ -96,6 +108,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu } if hasProtectedRole { + log.Debug("User is not assigned one of the protected roles", unasignedRoles) return res, fmt.Errorf(`invalid roles`) } else { user.Roles = existingUser.Roles + "," + strings.Join(unasignedRoles, ",") @@ -112,7 +125,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu user.SignupMethods = signupMethod user, _ = db.Provider.UpdateUser(user) if err != nil { - log.Println("error updating user:", err) + log.Debug("Failed to update user", err) } } @@ -121,6 +134,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu // insert verification request _, nonceHash, err := utils.GenerateNonce() if err != nil { + log.Debug("Failed to generate nonce", err) return res, err } redirectURLParams := "&roles=" + strings.Join(inputRoles, ",") @@ -144,7 +158,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu verificationType := constants.VerificationTypeMagicLinkLogin verificationToken, err := token.CreateVerificationToken(params.Email, verificationType, hostname, nonceHash, redirectURL) if err != nil { - log.Println(`error generating token`, err) + log.Debug("Failed to create verification token", err) } _, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: verificationToken, @@ -155,6 +169,7 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu RedirectURI: redirectURL, }) if err != nil { + log.Debug("Failed to add verification request in db:", err) return res, err } diff --git a/server/resolvers/profile.go b/server/resolvers/profile.go index 882f250..5ee2dc1 100644 --- a/server/resolvers/profile.go +++ b/server/resolvers/profile.go @@ -3,6 +3,8 @@ package resolvers import ( "context" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/token" @@ -11,25 +13,34 @@ import ( // ProfileResolver is a resolver for profile query func ProfileResolver(ctx context.Context) (*model.User, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.User + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } accessToken, err := token.GetAccessToken(gc) if err != nil { + log.Debug("Failed to get access token:", err) return res, err } claims, err := token.ValidateAccessToken(gc, accessToken) if err != nil { + log.Debug("Failed to validate access token:", err) return res, err } userID := claims["sub"].(string) + + log := log.WithFields(log.Fields{ + "user_id": userID, + }) user, err := db.Provider.GetUserByID(userID) if err != nil { + log.Debug("Failed to get user:", err) return res, err } diff --git a/server/resolvers/resend_verify_email.go b/server/resolvers/resend_verify_email.go index 68cb502..9e8fd82 100644 --- a/server/resolvers/resend_verify_email.go +++ b/server/resolvers/resend_verify_email.go @@ -3,10 +3,11 @@ package resolvers import ( "context" "fmt" - "log" "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/email" @@ -18,42 +19,48 @@ import ( // ResendVerifyEmailResolver is a resolver for resend verify email mutation func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEmailInput) (*model.Response, error) { var res *model.Response + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } params.Email = strings.ToLower(params.Email) if !utils.IsValidEmail(params.Email) { + log.Debug("Invalid email", params.Email) return res, fmt.Errorf("invalid email") } if !utils.IsValidVerificationIdentifier(params.Identifier) { + log.Debug("Invalid verification identifier", params.Identifier) return res, fmt.Errorf("invalid identifier") } verificationRequest, err := db.Provider.GetVerificationRequestByEmail(params.Email, params.Identifier) if err != nil { + log.Debug("Failed to get verification request", err) return res, fmt.Errorf(`verification request not found`) } // delete current verification and create new one err = db.Provider.DeleteVerificationRequest(verificationRequest) if err != nil { - log.Println("error deleting verification request:", err) + log.Debug("Failed to delete verification request", err) } hostname := utils.GetHost(gc) _, nonceHash, err := utils.GenerateNonce() if err != nil { + log.Debug("Failed to generate nonce", err) return res, err } verificationToken, err := token.CreateVerificationToken(params.Email, params.Identifier, hostname, nonceHash, verificationRequest.RedirectURI) if err != nil { - log.Println(`error generating token`, err) + log.Debug("Failed to create verification token", err) } - db.Provider.AddVerificationRequest(models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: verificationToken, Identifier: params.Identifier, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), @@ -61,6 +68,9 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma Nonce: nonceHash, RedirectURI: verificationRequest.RedirectURI, }) + if err != nil { + log.Debug("Failed to add verification request", err) + } // exec it as go routin so that we can reduce the api latency go email.SendVerificationMail(params.Email, verificationToken, hostname) diff --git a/server/resolvers/reset_password.go b/server/resolvers/reset_password.go index 8380fab..18cbd58 100644 --- a/server/resolvers/reset_password.go +++ b/server/resolvers/reset_password.go @@ -6,6 +6,8 @@ import ( "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/crypto" "github.com/authorizerdev/authorizer/server/db" @@ -18,24 +20,30 @@ import ( // ResetPasswordResolver is a resolver for reset password mutation func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) { var res *model.Response + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) { + log.Debug("Basic authentication is disabled") return res, fmt.Errorf(`basic authentication is disabled for this instance`) } verificationRequest, err := db.Provider.GetVerificationRequestByToken(params.Token) if err != nil { + log.Debug("Failed to get verification request", err) return res, fmt.Errorf(`invalid token`) } if params.Password != params.ConfirmPassword { + log.Debug("Passwords do not match") return res, fmt.Errorf(`passwords don't match`) } if !utils.IsValidPassword(params.Password) { + log.Debug("Invalid password") return res, fmt.Errorf(`password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character`) } @@ -43,11 +51,17 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) hostname := utils.GetHost(gc) claim, err := token.ParseJWTToken(params.Token, hostname, verificationRequest.Nonce, verificationRequest.Email) if err != nil { + log.Debug("Failed to parse token", err) return res, fmt.Errorf(`invalid token`) } - user, err := db.Provider.GetUserByEmail(claim["sub"].(string)) + email := claim["sub"].(string) + log := log.WithFields(log.Fields{ + "email": email, + }) + user, err := db.Provider.GetUserByEmail(email) if err != nil { + log.Debug("Failed to get user", err) return res, err } @@ -67,8 +81,17 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) } // delete from verification table - db.Provider.DeleteVerificationRequest(verificationRequest) - db.Provider.UpdateUser(user) + err = db.Provider.DeleteVerificationRequest(verificationRequest) + if err != nil { + log.Debug("Failed to delete verification request", err) + return res, err + } + + _, err = db.Provider.UpdateUser(user) + if err != nil { + log.Debug("Failed to update user", err) + return res, err + } res = &model.Response{ Message: `Password updated successfully.`, diff --git a/server/resolvers/revoke_access.go b/server/resolvers/revoke_access.go index a470be8..2bf5bb3 100644 --- a/server/resolvers/revoke_access.go +++ b/server/resolvers/revoke_access.go @@ -3,9 +3,10 @@ package resolvers import ( "context" "fmt" - "log" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/sessionstore" @@ -15,18 +16,25 @@ import ( // RevokeAccessResolver is a resolver for revoking user access func RevokeAccessResolver(ctx context.Context, params model.UpdateAccessInput) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return res, fmt.Errorf("unauthorized") } + log := log.WithFields(log.Fields{ + "user_id": params.UserID, + }) user, err := db.Provider.GetUserByID(params.UserID) if err != nil { + log.Debug("Failed to get user by ID", err) return res, err } @@ -35,7 +43,7 @@ func RevokeAccessResolver(ctx context.Context, params model.UpdateAccessInput) ( user, err = db.Provider.UpdateUser(user) if err != nil { - log.Println("error updating user:", err) + log.Debug("Failed to update user", err) return res, err } diff --git a/server/resolvers/session.go b/server/resolvers/session.go index 22e7171..d30be29 100644 --- a/server/resolvers/session.go +++ b/server/resolvers/session.go @@ -4,9 +4,10 @@ import ( "context" "errors" "fmt" - "log" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/graph/model" @@ -22,22 +23,28 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } sessionToken, err := cookie.GetSession(gc) if err != nil { - log.Println("error getting session token:", err) + log.Debug("Failed to get session token", err) return res, errors.New("unauthorized") } // get session from cookie claims, err := token.ValidateBrowserSession(gc, sessionToken) if err != nil { - log.Println("session validation failed:", err) + log.Debug("Failed to validate session token", err) return res, errors.New("unauthorized") } userID := claims.Subject + + log := log.WithFields(log.Fields{ + "user_id": userID, + }) + user, err := db.Provider.GetUserByID(userID) if err != nil { return res, err @@ -46,13 +53,12 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod // refresh token has "roles" as claim claimRoleInterface := claims.Roles claimRoles := []string{} - for _, v := range claimRoleInterface { - claimRoles = append(claimRoles, v) - } + claimRoles = append(claimRoles, claimRoleInterface...) if params != nil && params.Roles != nil && len(params.Roles) > 0 { for _, v := range params.Roles { if !utils.StringSliceContains(claimRoles, v) { + log.Debug("User does not have required role:", claimRoles, v) return res, fmt.Errorf(`unauthorized`) } } @@ -65,6 +71,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod authToken, err := token.CreateAuthToken(gc, user, claimRoles, scope) if err != nil { + log.Debug("Failed to create auth token", err) return res, err } diff --git a/server/resolvers/signup.go b/server/resolvers/signup.go index 3ed0e5d..34ebd7c 100644 --- a/server/resolvers/signup.go +++ b/server/resolvers/signup.go @@ -3,10 +3,11 @@ package resolvers import ( "context" "fmt" - "log" "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/crypto" @@ -22,44 +23,56 @@ import ( // SignupResolver is a resolver for signup mutation func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthResponse, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.AuthResponse + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) { + log.Debug("Signup is disabled.") return res, fmt.Errorf(`signup is disabled for this instance`) } if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) { + log.Debug("Basic authentication is disabled.") return res, fmt.Errorf(`basic authentication is disabled for this instance`) } if params.ConfirmPassword != params.Password { + log.Debug("Passwords do not match.") return res, fmt.Errorf(`password and confirm password does not match`) } if !utils.IsValidPassword(params.Password) { + log.Debug("Invalid password") return res, fmt.Errorf(`password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character`) } params.Email = strings.ToLower(params.Email) if !utils.IsValidEmail(params.Email) { + log.Debug("Invalid email:", params.Email) return res, fmt.Errorf(`invalid email address`) } + log := log.WithFields(log.Fields{ + "email": params.Email, + }) // find user with email existingUser, err := db.Provider.GetUserByEmail(params.Email) if err != nil { - log.Println("user with email " + params.Email + " not found") + log.Debug("Failed to get user by email:", err) } if existingUser.EmailVerifiedAt != nil { // email is verified + log.Debug("Email is already verified and signed up.") return res, fmt.Errorf(`%s has already signed up`, params.Email) } else if existingUser.ID != "" && existingUser.EmailVerifiedAt == nil { + log.Debug("Email is already signed up. Verification pending...") return res, fmt.Errorf("%s has already signed up. please complete the email verification process or reset the password", params.Email) } @@ -68,6 +81,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR if len(params.Roles) > 0 { // check if roles exists if !utils.IsValidRoles(envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyRoles), params.Roles) { + log.Debug("Invalid roles", params.Roles) return res, fmt.Errorf(`invalid roles`) } else { inputRoles = params.Roles @@ -124,6 +138,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR } user, err = db.Provider.AddUser(user) if err != nil { + log.Debug("Failed to add user:", err) return res, err } roles := strings.Split(user.Roles, ",") @@ -134,6 +149,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR // insert verification request _, nonceHash, err := utils.GenerateNonce() if err != nil { + log.Debug("Failed to generate nonce:", err) return res, err } verificationType := constants.VerificationTypeBasicAuthSignup @@ -143,9 +159,10 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR } verificationToken, err := token.CreateVerificationToken(params.Email, verificationType, hostname, nonceHash, redirectURL) if err != nil { + log.Debug("Failed to create verification token:", err) return res, err } - db.Provider.AddVerificationRequest(models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: verificationToken, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), @@ -153,6 +170,10 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR Nonce: nonceHash, RedirectURI: redirectURL, }) + if err != nil { + log.Debug("Failed to add verification request:", err) + return res, err + } // exec it as go routin so that we can reduce the api latency go email.SendVerificationMail(params.Email, verificationToken, hostname) @@ -169,6 +190,7 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR authToken, err := token.CreateAuthToken(gc, user, roles, scope) if err != nil { + log.Debug("Failed to create auth token:", err) return res, err } diff --git a/server/resolvers/update_env.go b/server/resolvers/update_env.go index 8da29d7..31e1a6e 100644 --- a/server/resolvers/update_env.go +++ b/server/resolvers/update_env.go @@ -5,9 +5,10 @@ import ( "encoding/json" "errors" "fmt" - "log" "reflect" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/crypto" @@ -23,14 +24,16 @@ import ( // UpdateEnvResolver is a resolver for update config mutation // This is admin only mutation func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return res, fmt.Errorf("unauthorized") } @@ -41,6 +44,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model if params.JwtType != nil { algo = *params.JwtType if !crypto.IsHMACA(algo) && !crypto.IsECDSA(algo) && !crypto.IsRSA(algo) { + log.Debug("Invalid JWT type", algo) return res, fmt.Errorf("invalid jwt type") } @@ -60,6 +64,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model // check if jwt secret is provided if crypto.IsHMACA(algo) { if params.JwtSecret == nil { + log.Debug("JWT secret is required for HMAC") return res, fmt.Errorf("jwt secret is required for HMAC algorithm") } @@ -70,6 +75,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model if crypto.IsRSA(algo) { if params.JwtPrivateKey == nil || params.JwtPublicKey == nil { + log.Debug("JWT private key and public key are required for RSA", params.JwtPrivateKey, params.JwtPublicKey) return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm") } @@ -77,17 +83,20 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model params.JwtSecret = &defaultSecret _, err = crypto.ParseRsaPrivateKeyFromPemStr(*params.JwtPrivateKey) if err != nil { + log.Debug("Invalid JWT private key", err) return res, err } _, err := crypto.ParseRsaPublicKeyFromPemStr(*params.JwtPublicKey) if err != nil { + log.Debug("Invalid JWT public key", err) return res, err } } if crypto.IsECDSA(algo) { if params.JwtPrivateKey == nil || params.JwtPublicKey == nil { + log.Debug("JWT private key and public key are required for ECDSA", params.JwtPrivateKey, params.JwtPublicKey) return res, fmt.Errorf("jwt private and public key is required for RSA (PKCS1) / ECDSA algorithm") } @@ -95,11 +104,13 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model params.JwtSecret = &defaultSecret _, err = crypto.ParseEcdsaPrivateKeyFromPemStr(*params.JwtPrivateKey) if err != nil { + log.Debug("Invalid JWT private key", err) return res, err } _, err := crypto.ParseEcdsaPublicKeyFromPemStr(*params.JwtPublicKey) if err != nil { + log.Debug("Invalid JWT public key", err) return res, err } } @@ -109,25 +120,30 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model var data map[string]interface{} byteData, err := json.Marshal(params) if err != nil { + log.Debug("Failed to marshal update env input", err) return res, fmt.Errorf("error marshalling params: %t", err) } err = json.Unmarshal(byteData, &data) if err != nil { + log.Debug("Failed to unmarshal update env input", err) return res, fmt.Errorf("error un-marshalling params: %t", err) } // in case of admin secret change update the cookie with new hash if params.AdminSecret != nil { if params.OldAdminSecret == nil { + log.Debug("Old admin secret is required for admin secret update") return res, errors.New("admin secret and old admin secret are required for secret change") } if *params.OldAdminSecret != envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret) { + log.Debug("Old admin secret is invalid") return res, errors.New("old admin secret is not correct") } if len(*params.AdminSecret) < 6 { + log.Debug("Admin secret is too short") err = fmt.Errorf("admin secret must be at least 6 characters") return res, err } @@ -173,6 +189,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model // should be subset of roles for _, role := range params.DefaultRoles { if !utils.StringSliceContains(params.Roles, role) { + log.Debug("Default roles should be subset of roles") return res, fmt.Errorf("default role %s is not in roles", role) } } @@ -182,6 +199,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model if len(params.ProtectedRoles) > 0 { for _, role := range params.ProtectedRoles { if utils.StringSliceContains(params.Roles, role) || utils.StringSliceContains(params.DefaultRoles, role) { + 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) } } @@ -191,12 +209,14 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model envstore.EnvStoreObj.UpdateEnvStore(updatedData) jwk, err := crypto.GenerateJWKBasedOnEnv() if err != nil { + log.Debug("Failed to generate JWK", err) return res, err } // updating jwk envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJWK, jwk) err = sessionstore.InitSession() if err != nil { + log.Debug("Failed to init session store", err) return res, err } err = oauth.InitOAuth() @@ -207,12 +227,14 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model // Fetch the current db store and update it env, err := db.Provider.GetEnv() if err != nil { + log.Debug("Failed to get env", err) return res, err } if params.AdminSecret != nil { hashedKey, err := crypto.EncryptPassword(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAdminSecret)) if err != nil { + log.Debug("Failed to encrypt admin secret", err) return res, err } cookie.SetAdminCookie(gc, hashedKey) @@ -220,13 +242,14 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model encryptedConfig, err := crypto.EncryptEnvData(updatedData) if err != nil { + log.Debug("Failed to encrypt env data", err) return res, err } env.EnvData = encryptedConfig _, err = db.Provider.UpdateEnv(env) if err != nil { - log.Println("error updating config:", err) + log.Debug("Failed to update env", err) return res, err } diff --git a/server/resolvers/update_profile.go b/server/resolvers/update_profile.go index 73e87fe..cafe2a3 100644 --- a/server/resolvers/update_profile.go +++ b/server/resolvers/update_profile.go @@ -3,10 +3,11 @@ package resolvers import ( "context" "fmt" - "log" "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/crypto" @@ -23,18 +24,22 @@ import ( // UpdateProfileResolver is resolver for update profile mutation func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) (*model.Response, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.Response + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } accessToken, err := token.GetAccessToken(gc) if err != nil { + log.Debug("Failed to get access token", err) return res, err } claims, err := token.ValidateAccessToken(gc, accessToken) if err != nil { + log.Debug("Failed to validate access token", err) return res, err } @@ -44,8 +49,13 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) } userID := claims["sub"].(string) + log := log.WithFields(log.Fields{ + "user_id": userID, + }) + user, err := db.Provider.GetUserByID(userID) if err != nil { + log.Debug("Failed to get user by id", err) return res, err } @@ -83,18 +93,22 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) if params.OldPassword != nil { if err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(*params.OldPassword)); err != nil { + log.Debug("Failed to compare hash and old password", err) return res, fmt.Errorf("incorrect old password") } if params.NewPassword == nil { + log.Debug("Failed to get new password") return res, fmt.Errorf("new password is required") } if params.ConfirmNewPassword == nil { + log.Debug("Failed to get confirm new password") return res, fmt.Errorf("confirm password is required") } if *params.ConfirmNewPassword != *params.NewPassword { + log.Debug("Failed to compare new password and confirm new password") return res, fmt.Errorf(`password and confirm password does not match`) } @@ -108,6 +122,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) if params.Email != nil && user.Email != *params.Email { // check if valid email if !utils.IsValidEmail(*params.Email) { + log.Debug("Failed to validate email", *params.Email) return res, fmt.Errorf("invalid email address") } newEmail := strings.ToLower(*params.Email) @@ -115,15 +130,14 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) _, err := db.Provider.GetUserByEmail(newEmail) // err = nil means user exists if err == nil { + log.Debug("Failed to get user by email", newEmail) return res, fmt.Errorf("user with this email address already exists") } - // TODO figure out how to delete all user sessions go sessionstore.DeleteAllUserSession(user.ID) + go cookie.DeleteSession(gc) - cookie.DeleteSession(gc) user.Email = newEmail - if !envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) { hostname := utils.GetHost(gc) user.EmailVerifiedAt = nil @@ -131,15 +145,17 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) // insert verification request _, nonceHash, err := utils.GenerateNonce() if err != nil { + log.Debug("Failed to generate nonce", err) return res, err } verificationType := constants.VerificationTypeUpdateEmail redirectURL := utils.GetAppURL(gc) verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname, nonceHash, redirectURL) if err != nil { - log.Println(`error generating token`, err) + log.Debug("Failed to create verification token", err) + return res, err } - db.Provider.AddVerificationRequest(models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: verificationToken, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), @@ -147,6 +163,10 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) Nonce: nonceHash, RedirectURI: redirectURL, }) + if err != nil { + log.Debug("Failed to add verification request", err) + return res, err + } // exec it as go routin so that we can reduce the api latency go email.SendVerificationMail(newEmail, verificationToken, hostname) @@ -155,7 +175,7 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput) } _, err = db.Provider.UpdateUser(user) if err != nil { - log.Println("error updating user:", err) + log.Debug("Failed to update user", err) return res, err } message := `Profile details updated successfully.` diff --git a/server/resolvers/update_user.go b/server/resolvers/update_user.go index a759399..811e1b3 100644 --- a/server/resolvers/update_user.go +++ b/server/resolvers/update_user.go @@ -3,10 +3,11 @@ package resolvers import ( "context" "fmt" - "log" "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db/models" @@ -21,22 +22,36 @@ import ( // UpdateUserResolver is a resolver for update user mutation // This is admin only mutation func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*model.User, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.User + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return res, fmt.Errorf("unauthorized") } + if params.ID == "" { + log.Debug("Invalid user id") + return res, fmt.Errorf("User ID is required") + } + + log := log.WithFields(log.Fields{ + "user_id": params.ID, + }) + if params.GivenName == nil && params.FamilyName == nil && params.Picture == nil && params.MiddleName == nil && params.Nickname == nil && params.Email == nil && params.Birthdate == nil && params.Gender == nil && params.PhoneNumber == nil && params.Roles == nil { + log.Debug("No params to update") return res, fmt.Errorf("please enter atleast one param to update") } user, err := db.Provider.GetUserByID(params.ID) if err != nil { + log.Debug("Failed to get user by id", err) return res, fmt.Errorf(`User not found`) } @@ -84,6 +99,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod if params.Email != nil && user.Email != *params.Email { // check if valid email if !utils.IsValidEmail(*params.Email) { + log.Debug("Invalid email", *params.Email) return res, fmt.Errorf("invalid email address") } newEmail := strings.ToLower(*params.Email) @@ -91,6 +107,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod _, err = db.Provider.GetUserByEmail(newEmail) // err = nil means user exists if err == nil { + log.Debug("User with email already exists", newEmail) return res, fmt.Errorf("user with this email address already exists") } @@ -103,15 +120,16 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod // insert verification request _, nonceHash, err := utils.GenerateNonce() if err != nil { + log.Debug("Failed to generate nonce", err) return res, err } verificationType := constants.VerificationTypeUpdateEmail redirectURL := utils.GetAppURL(gc) verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname, nonceHash, redirectURL) if err != nil { - log.Println(`error generating token`, err) + log.Debug("Failed to create verification token", err) } - db.Provider.AddVerificationRequest(models.VerificationRequest{ + _, err = db.Provider.AddVerificationRequest(models.VerificationRequest{ Token: verificationToken, Identifier: verificationType, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), @@ -119,6 +137,10 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod Nonce: nonceHash, RedirectURI: redirectURL, }) + if err != nil { + log.Debug("Failed to add verification request", err) + return res, err + } // exec it as go routin so that we can reduce the api latency go email.SendVerificationMail(newEmail, verificationToken, hostname) @@ -134,6 +156,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod } if !utils.IsValidRoles(inputRoles, append([]string{}, append(envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyRoles), envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyProtectedRoles)...)...)) { + log.Debug("Invalid roles", params.Roles) return res, fmt.Errorf("invalid list of roles") } @@ -150,7 +173,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod user, err = db.Provider.UpdateUser(user) if err != nil { - log.Println("error updating user:", err) + log.Debug("Failed to update user", err) return res, err } diff --git a/server/resolvers/users.go b/server/resolvers/users.go index 987f4bb..ec39f86 100644 --- a/server/resolvers/users.go +++ b/server/resolvers/users.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/token" @@ -15,10 +17,12 @@ import ( func UsersResolver(ctx context.Context, params *model.PaginatedInput) (*model.Users, error) { gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return nil, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return nil, fmt.Errorf("unauthorized") } @@ -26,6 +30,7 @@ func UsersResolver(ctx context.Context, params *model.PaginatedInput) (*model.Us res, err := db.Provider.ListUsers(pagination) if err != nil { + log.Debug("Failed to get users", err) return nil, err } diff --git a/server/resolvers/validate_jwt_token.go b/server/resolvers/validate_jwt_token.go index ce1c84c..9adf802 100644 --- a/server/resolvers/validate_jwt_token.go +++ b/server/resolvers/validate_jwt_token.go @@ -6,11 +6,13 @@ import ( "fmt" "strings" + "github.com/golang-jwt/jwt" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" - "github.com/golang-jwt/jwt" ) // ValidateJwtTokenResolver is used to validate a jwt token without its rotation @@ -22,11 +24,13 @@ import ( func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTTokenInput) (*model.ValidateJWTTokenResponse, error) { gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return nil, err } tokenType := params.TokenType if tokenType != "access_token" && tokenType != "refresh_token" && tokenType != "id_token" { + log.Debug("Invalid token type:", tokenType) return nil, errors.New("invalid token type") } @@ -53,6 +57,7 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken if userID != "" && nonce != "" { claims, err = token.ParseJWTToken(params.Token, hostname, nonce, userID) if err != nil { + log.Debug("Failed to parse jwt token", err) return &model.ValidateJWTTokenResponse{ IsValid: false, }, nil @@ -60,6 +65,7 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken } else { claims, err = token.ParseJWTTokenWithoutNonce(params.Token, hostname) if err != nil { + log.Debug("Failed to parse jwt token without nonce", err) return &model.ValidateJWTTokenResponse{ IsValid: false, }, nil @@ -76,6 +82,7 @@ func ValidateJwtTokenResolver(ctx context.Context, params model.ValidateJWTToken if params.Roles != nil && len(params.Roles) > 0 { for _, v := range params.Roles { if !utils.StringSliceContains(claimRoles, v) { + log.Debug("Token does not have required role:", v) return nil, fmt.Errorf(`unauthorized`) } } diff --git a/server/resolvers/verification_requests.go b/server/resolvers/verification_requests.go index ff5420d..85fd202 100644 --- a/server/resolvers/verification_requests.go +++ b/server/resolvers/verification_requests.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/token" @@ -15,10 +17,12 @@ import ( func VerificationRequestsResolver(ctx context.Context, params *model.PaginatedInput) (*model.VerificationRequests, error) { gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return nil, err } if !token.IsSuperAdmin(gc) { + log.Debug("Not logged in as super admin.") return nil, fmt.Errorf("unauthorized") } @@ -26,6 +30,7 @@ func VerificationRequestsResolver(ctx context.Context, params *model.PaginatedIn res, err := db.Provider.ListVerificationRequests(pagination) if err != nil { + log.Debug("Failed to get verification requests", err) return nil, err } diff --git a/server/resolvers/verify_email.go b/server/resolvers/verify_email.go index 95e19da..18cf93d 100644 --- a/server/resolvers/verify_email.go +++ b/server/resolvers/verify_email.go @@ -6,6 +6,8 @@ import ( "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db/models" @@ -17,14 +19,17 @@ import ( // VerifyEmailResolver is a resolver for verify email mutation func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*model.AuthResponse, error) { - gc, err := utils.GinContextFromContext(ctx) var res *model.AuthResponse + + gc, err := utils.GinContextFromContext(ctx) if err != nil { + log.Debug("Failed to get GinContext", err) return res, err } verificationRequest, err := db.Provider.GetVerificationRequestByToken(params.Token) if err != nil { + log.Debug("Failed to get verification request by token", err) return res, fmt.Errorf(`invalid token: %s`, err.Error()) } @@ -32,11 +37,17 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m hostname := utils.GetHost(gc) claim, err := token.ParseJWTToken(params.Token, hostname, verificationRequest.Nonce, verificationRequest.Email) if err != nil { + log.Debug("Failed to parse token", err) return res, fmt.Errorf(`invalid token: %s`, err.Error()) } - user, err := db.Provider.GetUserByEmail(claim["sub"].(string)) + email := claim["sub"].(string) + log := log.WithFields(log.Fields{ + "email": email, + }) + user, err := db.Provider.GetUserByEmail(email) if err != nil { + log.Debug("Failed to get user by email", err) return res, err } @@ -45,11 +56,13 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m user.EmailVerifiedAt = &now user, err = db.Provider.UpdateUser(user) if err != nil { + log.Debug("Failed to update user", err) return res, err } // delete from verification table err = db.Provider.DeleteVerificationRequest(verificationRequest) if err != nil { + log.Debug("Failed to delete verification request", err) return res, err } @@ -57,6 +70,7 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m scope := []string{"openid", "email", "profile"} authToken, err := token.CreateAuthToken(gc, user, roles, scope) if err != nil { + log.Debug("Failed to create auth token", err) return res, err }