diff --git a/server/db/db.go b/server/db/db.go index 70b1033..a93cc01 100644 --- a/server/db/db.go +++ b/server/db/db.go @@ -1,6 +1,8 @@ package db import ( + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db/providers" "github.com/authorizerdev/authorizer/server/db/providers/arangodb" @@ -22,29 +24,37 @@ func InitDB() error { isCassandra := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) == constants.DbTypeCassandraDB if isSQL { + log.Info("Initializing SQL Driver for: ", envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType)) Provider, err = sql.NewProvider() if err != nil { + log.Fatal("Failed to initialize SQL driver: ", err) return err } } if isArangoDB { + log.Info("Initializing ArangoDB Driver") Provider, err = arangodb.NewProvider() if err != nil { + log.Fatal("Failed to initialize ArangoDB driver: ", err) return err } } if isMongoDB { + log.Info("Initializing MongoDB Driver") Provider, err = mongodb.NewProvider() if err != nil { + log.Fatal("Failed to initialize MongoDB driver: ", err) return err } } if isCassandra { + log.Info("Initializing CassandraDB Driver") Provider, err = cassandradb.NewProvider() if err != nil { + log.Fatal("Failed to initialize CassandraDB driver: ", err) return err } } diff --git a/server/db/providers/arangodb/env.go b/server/db/providers/arangodb/env.go index c2d866f..6931095 100644 --- a/server/db/providers/arangodb/env.go +++ b/server/db/providers/arangodb/env.go @@ -2,7 +2,6 @@ package arangodb import ( "fmt" - "log" "time" arangoDriver "github.com/arangodb/go-driver" @@ -22,7 +21,6 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) { configCollection, _ := p.db.Collection(nil, models.Collections.Env) meta, err := configCollection.CreateDocument(arangoDriver.WithOverwrite(nil), env) if err != nil { - log.Println("error adding config:", err) return env, err } env.Key = meta.Key @@ -36,7 +34,6 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { collection, _ := p.db.Collection(nil, models.Collections.Env) meta, err := collection.UpdateDocument(nil, env.Key, env) if err != nil { - log.Println("error updating config:", err) return env, err } diff --git a/server/db/providers/arangodb/provider.go b/server/db/providers/arangodb/provider.go index 9866ed2..92c007c 100644 --- a/server/db/providers/arangodb/provider.go +++ b/server/db/providers/arangodb/provider.go @@ -2,7 +2,6 @@ package arangodb import ( "context" - "log" "github.com/arangodb/go-driver" arangoDriver "github.com/arangodb/go-driver" @@ -42,7 +41,6 @@ func NewProvider() (*provider, error) { arangodb_exists, err := arangoClient.DatabaseExists(nil, envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName)) if arangodb_exists { - log.Println(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName) + " db exists already") arangodb, err = arangoClient.Database(nil, envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseName)) if err != nil { return nil, err @@ -55,12 +53,10 @@ func NewProvider() (*provider, error) { } userCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.User) - if userCollectionExists { - log.Println(models.Collections.User + " collection exists already") - } else { + if !userCollectionExists { _, err = arangodb.CreateCollection(ctx, models.Collections.User, nil) if err != nil { - log.Println("error creating collection("+models.Collections.User+"):", err) + return nil, err } } userCollection, _ := arangodb.Collection(nil, models.Collections.User) @@ -74,12 +70,10 @@ func NewProvider() (*provider, error) { }) verificationRequestCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.VerificationRequest) - if verificationRequestCollectionExists { - log.Println(models.Collections.VerificationRequest + " collection exists already") - } else { + if !verificationRequestCollectionExists { _, err = arangodb.CreateCollection(ctx, models.Collections.VerificationRequest, nil) if err != nil { - log.Println("error creating collection("+models.Collections.VerificationRequest+"):", err) + return nil, err } } @@ -93,12 +87,10 @@ func NewProvider() (*provider, error) { }) sessionCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Session) - if sessionCollectionExists { - log.Println(models.Collections.Session + " collection exists already") - } else { + if !sessionCollectionExists { _, err = arangodb.CreateCollection(ctx, models.Collections.Session, nil) if err != nil { - log.Println("error creating collection("+models.Collections.Session+"):", err) + return nil, err } } @@ -108,12 +100,10 @@ func NewProvider() (*provider, error) { }) configCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.Env) - if configCollectionExists { - log.Println(models.Collections.Env + " collection exists already") - } else { + if !configCollectionExists { _, err = arangodb.CreateCollection(ctx, models.Collections.Env, nil) if err != nil { - log.Println("error creating collection("+models.Collections.Env+"):", err) + return nil, err } } diff --git a/server/db/providers/arangodb/session.go b/server/db/providers/arangodb/session.go index 2623a1a..4bda894 100644 --- a/server/db/providers/arangodb/session.go +++ b/server/db/providers/arangodb/session.go @@ -2,7 +2,6 @@ package arangodb import ( "fmt" - "log" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -20,7 +19,6 @@ func (p *provider) AddSession(session models.Session) error { sessionCollection, _ := p.db.Collection(nil, models.Collections.Session) _, err := sessionCollection.CreateDocument(nil, session) if err != nil { - log.Println(`error saving session`, err) return err } return nil diff --git a/server/db/providers/arangodb/user.go b/server/db/providers/arangodb/user.go index fb011b3..fc466a4 100644 --- a/server/db/providers/arangodb/user.go +++ b/server/db/providers/arangodb/user.go @@ -3,7 +3,6 @@ package arangodb import ( "context" "fmt" - "log" "strings" "time" @@ -31,7 +30,6 @@ func (p *provider) AddUser(user models.User) (models.User, error) { userCollection, _ := p.db.Collection(nil, models.Collections.User) meta, err := userCollection.CreateDocument(arangoDriver.WithOverwrite(nil), user) if err != nil { - log.Println("error adding user:", err) return user, err } user.Key = meta.Key @@ -46,7 +44,6 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) { collection, _ := p.db.Collection(nil, models.Collections.User) meta, err := collection.UpdateDocument(nil, user.Key, user) if err != nil { - log.Println("error updating user:", err) return user, err } @@ -60,7 +57,6 @@ func (p *provider) DeleteUser(user models.User) error { collection, _ := p.db.Collection(nil, models.Collections.User) _, err := collection.RemoveDocument(nil, user.Key) if err != nil { - log.Println(`error deleting user:`, err) return err } diff --git a/server/db/providers/arangodb/verification_requests.go b/server/db/providers/arangodb/verification_requests.go index a5a9fe1..ef7ee20 100644 --- a/server/db/providers/arangodb/verification_requests.go +++ b/server/db/providers/arangodb/verification_requests.go @@ -3,7 +3,6 @@ package arangodb import ( "context" "fmt" - "log" "time" "github.com/arangodb/go-driver" @@ -23,7 +22,6 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio verificationRequestRequestCollection, _ := p.db.Collection(nil, models.Collections.VerificationRequest) meta, err := verificationRequestRequestCollection.CreateDocument(nil, verificationRequest) if err != nil { - log.Println("error saving verificationRequest record:", err) return verificationRequest, err } verificationRequest.Key = meta.Key @@ -136,7 +134,6 @@ func (p *provider) DeleteVerificationRequest(verificationRequest models.Verifica collection, _ := p.db.Collection(nil, models.Collections.VerificationRequest) _, err := collection.RemoveDocument(nil, verificationRequest.Key) if err != nil { - log.Println(`error deleting verification request:`, err) return err } return nil diff --git a/server/db/providers/cassandradb/provider.go b/server/db/providers/cassandradb/provider.go index 6e0dd64..e7bf3b0 100644 --- a/server/db/providers/cassandradb/provider.go +++ b/server/db/providers/cassandradb/provider.go @@ -4,7 +4,6 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "log" "strings" "github.com/authorizerdev/authorizer/server/constants" @@ -88,7 +87,6 @@ func NewProvider() (*provider, error) { session, err := cassandraClient.CreateSession() if err != nil { - log.Println("Error while creating connection to cassandra db", err) return nil, err } @@ -101,7 +99,6 @@ func NewProvider() (*provider, error) { var keySpace string err := scanner.Scan(&keySpace) if err != nil { - log.Println("Error while getting keyspace information", err) return nil, err } if keySpace == KeySpace { @@ -114,7 +111,6 @@ func NewProvider() (*provider, error) { createKeySpaceQuery := fmt.Sprintf("CREATE KEYSPACE %s WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1};", KeySpace) err = session.Query(createKeySpaceQuery).Exec() if err != nil { - log.Println("Error while creating keyspace", err) return nil, err } } @@ -124,27 +120,23 @@ func NewProvider() (*provider, error) { KeySpace, models.Collections.Env) err = session.Query(envCollectionQuery).Exec() if err != nil { - log.Println("Unable to create env collection:", err) return nil, err } sessionCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, user_id text, user_agent text, ip text, updated_at bigint, created_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.Session) err = session.Query(sessionCollectionQuery).Exec() if err != nil { - log.Println("Unable to create session collection:", err) return nil, err } userCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, email text, email_verified_at bigint, password text, signup_methods text, given_name text, family_name text, middle_name text, nickname text, gender text, birthdate text, phone_number text, phone_number_verified_at bigint, picture text, roles text, updated_at bigint, created_at bigint, revoked_timestamp bigint, PRIMARY KEY (id))", KeySpace, models.Collections.User) err = session.Query(userCollectionQuery).Exec() if err != nil { - log.Println("Unable to create user collection:", err) return nil, err } userIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_user_email ON %s.%s (email)", KeySpace, models.Collections.User) err = session.Query(userIndexQuery).Exec() if err != nil { - log.Println("Unable to create user index:", err) return nil, err } @@ -152,25 +144,21 @@ func NewProvider() (*provider, error) { verificationRequestCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, jwt_token text, identifier text, expires_at bigint, email text, nonce text, redirect_uri text, created_at bigint, updated_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.VerificationRequest) err = session.Query(verificationRequestCollectionQuery).Exec() if err != nil { - log.Println("Unable to create verification request collection:", err) return nil, err } verificationRequestIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_verification_request_email ON %s.%s (email)", KeySpace, models.Collections.VerificationRequest) err = session.Query(verificationRequestIndexQuery).Exec() if err != nil { - log.Println("Unable to create verification_requests index:", err) return nil, err } verificationRequestIndexQuery = fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_verification_request_identifier ON %s.%s (identifier)", KeySpace, models.Collections.VerificationRequest) err = session.Query(verificationRequestIndexQuery).Exec() if err != nil { - log.Println("Unable to create verification_requests index:", err) return nil, err } verificationRequestIndexQuery = fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_verification_request_jwt_token ON %s.%s (jwt_token)", KeySpace, models.Collections.VerificationRequest) err = session.Query(verificationRequestIndexQuery).Exec() if err != nil { - log.Println("Unable to create verification_requests index:", err) return nil, err } diff --git a/server/db/providers/cassandradb/verification_requests.go b/server/db/providers/cassandradb/verification_requests.go index 6c82462..18476ac 100644 --- a/server/db/providers/cassandradb/verification_requests.go +++ b/server/db/providers/cassandradb/verification_requests.go @@ -2,7 +2,6 @@ package cassandradb import ( "fmt" - "log" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -61,7 +60,6 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model totalCountQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s`, KeySpace+"."+models.Collections.VerificationRequest) err := p.db.Query(totalCountQuery).Consistency(gocql.One).Scan(&paginationClone.Total) if err != nil { - log.Println("Error while quering verification request", err) return nil, err } @@ -77,7 +75,6 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model var verificationRequest models.VerificationRequest err := scanner.Scan(&verificationRequest.ID, &verificationRequest.Token, &verificationRequest.Identifier, &verificationRequest.ExpiresAt, &verificationRequest.Email, &verificationRequest.Nonce, &verificationRequest.RedirectURI, &verificationRequest.CreatedAt, &verificationRequest.UpdatedAt) if err != nil { - log.Println("Error while parsing verification request", err) return nil, err } verificationRequests = append(verificationRequests, verificationRequest.AsAPIVerificationRequest()) diff --git a/server/db/providers/mongodb/env.go b/server/db/providers/mongodb/env.go index 0d144e6..6d17adf 100644 --- a/server/db/providers/mongodb/env.go +++ b/server/db/providers/mongodb/env.go @@ -2,7 +2,6 @@ package mongodb import ( "fmt" - "log" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -23,7 +22,6 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) { configCollection := p.db.Collection(models.Collections.Env, options.Collection()) _, err := configCollection.InsertOne(nil, env) if err != nil { - log.Println("error adding config:", err) return env, err } return env, nil @@ -35,7 +33,6 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { configCollection := p.db.Collection(models.Collections.Env, options.Collection()) _, err := configCollection.UpdateOne(nil, bson.M{"_id": bson.M{"$eq": env.ID}}, bson.M{"$set": env}, options.MergeUpdateOptions()) if err != nil { - log.Println("error updating config:", err) return env, err } return env, nil diff --git a/server/db/providers/mongodb/session.go b/server/db/providers/mongodb/session.go index 88c492f..c4c04c8 100644 --- a/server/db/providers/mongodb/session.go +++ b/server/db/providers/mongodb/session.go @@ -1,7 +1,6 @@ package mongodb import ( - "log" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -22,7 +21,6 @@ func (p *provider) AddSession(session models.Session) error { sessionCollection := p.db.Collection(models.Collections.Session, options.Collection()) _, err := sessionCollection.InsertOne(nil, session) if err != nil { - log.Println(`error saving session`, err) return err } return nil @@ -33,7 +31,6 @@ func (p *provider) DeleteSession(userId string) error { sessionCollection := p.db.Collection(models.Collections.Session, options.Collection()) _, err := sessionCollection.DeleteMany(nil, bson.M{"user_id": userId}, options.Delete()) if err != nil { - log.Println("error deleting session:", err) return err } return nil diff --git a/server/db/providers/mongodb/user.go b/server/db/providers/mongodb/user.go index 28d7d44..af6c799 100644 --- a/server/db/providers/mongodb/user.go +++ b/server/db/providers/mongodb/user.go @@ -1,7 +1,6 @@ package mongodb import ( - "log" "strings" "time" @@ -29,7 +28,6 @@ func (p *provider) AddUser(user models.User) (models.User, error) { userCollection := p.db.Collection(models.Collections.User, options.Collection()) _, err := userCollection.InsertOne(nil, user) if err != nil { - log.Println("error adding user:", err) return user, err } @@ -42,7 +40,6 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) { userCollection := p.db.Collection(models.Collections.User, options.Collection()) _, err := userCollection.UpdateOne(nil, bson.M{"_id": bson.M{"$eq": user.ID}}, bson.M{"$set": user}, options.MergeUpdateOptions()) if err != nil { - log.Println("error updating user:", err) return user, err } return user, nil @@ -53,7 +50,6 @@ func (p *provider) DeleteUser(user models.User) error { userCollection := p.db.Collection(models.Collections.User, options.Collection()) _, err := userCollection.DeleteOne(nil, bson.M{"_id": user.ID}, options.Delete()) if err != nil { - log.Println("error deleting user:", err) return err } @@ -74,7 +70,6 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error) userCollection := p.db.Collection(models.Collections.User, options.Collection()) count, err := userCollection.CountDocuments(nil, bson.M{}, options.Count()) if err != nil { - log.Println("error getting total users:", err) return nil, err } @@ -82,7 +77,6 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error) cursor, err := userCollection.Find(nil, bson.M{}, opts) if err != nil { - log.Println("error getting users:", err) return nil, err } defer cursor.Close(nil) diff --git a/server/db/providers/mongodb/verification_requests.go b/server/db/providers/mongodb/verification_requests.go index 2776a83..c931982 100644 --- a/server/db/providers/mongodb/verification_requests.go +++ b/server/db/providers/mongodb/verification_requests.go @@ -1,7 +1,6 @@ package mongodb import ( - "log" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -22,7 +21,6 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) _, err := verificationRequestCollection.InsertOne(nil, verificationRequest) if err != nil { - log.Println("error saving verification record:", err) return verificationRequest, err } } @@ -73,7 +71,6 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model cursor, err := verificationRequestCollection.Find(nil, bson.M{}, opts) if err != nil { - log.Println("error getting verification requests:", err) return nil, err } defer cursor.Close(nil) @@ -98,7 +95,6 @@ func (p *provider) DeleteVerificationRequest(verificationRequest models.Verifica verificationRequestCollection := p.db.Collection(models.Collections.VerificationRequest, options.Collection()) _, err := verificationRequestCollection.DeleteOne(nil, bson.M{"_id": verificationRequest.ID}, options.Delete()) if err != nil { - log.Println("error deleting verification request::", err) return err } diff --git a/server/db/providers/sql/env.go b/server/db/providers/sql/env.go index 9df14ae..13b45a4 100644 --- a/server/db/providers/sql/env.go +++ b/server/db/providers/sql/env.go @@ -1,7 +1,6 @@ package sql import ( - "log" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -20,7 +19,6 @@ func (p *provider) AddEnv(env models.Env) (models.Env, error) { result := p.db.Create(&env) if result.Error != nil { - log.Println("error adding config:", result.Error) return env, result.Error } return env, nil @@ -32,7 +30,6 @@ func (p *provider) UpdateEnv(env models.Env) (models.Env, error) { result := p.db.Save(&env) if result.Error != nil { - log.Println("error updating config:", result.Error) return env, result.Error } return env, nil diff --git a/server/db/providers/sql/session.go b/server/db/providers/sql/session.go index 8184558..4e7e7f1 100644 --- a/server/db/providers/sql/session.go +++ b/server/db/providers/sql/session.go @@ -1,7 +1,6 @@ package sql import ( - "log" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -23,7 +22,6 @@ func (p *provider) AddSession(session models.Session) error { DoNothing: true, }).Create(&session) if res.Error != nil { - log.Println(`error saving session`, res.Error) return res.Error } return nil @@ -34,7 +32,6 @@ func (p *provider) DeleteSession(userId string) error { result := p.db.Where("user_id = ?", userId).Delete(&models.Session{}) if result.Error != nil { - log.Println(`error deleting session:`, result.Error) return result.Error } return nil diff --git a/server/db/providers/sql/user.go b/server/db/providers/sql/user.go index 7d0049a..ef295c6 100644 --- a/server/db/providers/sql/user.go +++ b/server/db/providers/sql/user.go @@ -1,7 +1,6 @@ package sql import ( - "log" "strings" "time" @@ -33,7 +32,6 @@ func (p *provider) AddUser(user models.User) (models.User, error) { }).Create(&user) if result.Error != nil { - log.Println("error adding user:", result.Error) return user, result.Error } @@ -47,7 +45,6 @@ func (p *provider) UpdateUser(user models.User) (models.User, error) { result := p.db.Save(&user) if result.Error != nil { - log.Println("error updating user:", result.Error) return user, result.Error } @@ -59,7 +56,6 @@ func (p *provider) DeleteUser(user models.User) error { result := p.db.Delete(&user) if result.Error != nil { - log.Println(`error deleting user:`, result.Error) return result.Error } @@ -71,7 +67,6 @@ func (p *provider) ListUsers(pagination model.Pagination) (*model.Users, error) var users []models.User result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&users) if result.Error != nil { - log.Println("error getting users:", result.Error) return nil, result.Error } diff --git a/server/db/providers/sql/verification_requests.go b/server/db/providers/sql/verification_requests.go index fe044a7..934d4cd 100644 --- a/server/db/providers/sql/verification_requests.go +++ b/server/db/providers/sql/verification_requests.go @@ -1,7 +1,6 @@ package sql import ( - "log" "time" "github.com/authorizerdev/authorizer/server/db/models" @@ -25,7 +24,6 @@ func (p *provider) AddVerificationRequest(verificationRequest models.Verificatio }).Create(&verificationRequest) if result.Error != nil { - log.Println(`error saving verification request record`, result.Error) return verificationRequest, result.Error } @@ -38,7 +36,6 @@ func (p *provider) GetVerificationRequestByToken(token string) (models.Verificat result := p.db.Where("token = ?", token).First(&verificationRequest) if result.Error != nil { - log.Println(`error getting verification request:`, result.Error) return verificationRequest, result.Error } @@ -52,7 +49,6 @@ func (p *provider) GetVerificationRequestByEmail(email string, identifier string result := p.db.Where("email = ? AND identifier = ?", email, identifier).First(&verificationRequest) if result.Error != nil { - log.Println(`error getting verification token:`, result.Error) return verificationRequest, result.Error } @@ -65,7 +61,6 @@ func (p *provider) ListVerificationRequests(pagination model.Pagination) (*model result := p.db.Limit(int(pagination.Limit)).Offset(int(pagination.Offset)).Order("created_at DESC").Find(&verificationRequests) if result.Error != nil { - log.Println("error getting verification requests:", result.Error) return nil, result.Error } @@ -94,7 +89,6 @@ func (p *provider) DeleteVerificationRequest(verificationRequest models.Verifica result := p.db.Delete(&verificationRequest) if result.Error != nil { - log.Println(`error deleting verification request:`, result.Error) return result.Error } diff --git a/server/email/email.go b/server/email/email.go index 7b423d2..b8e6d80 100644 --- a/server/email/email.go +++ b/server/email/email.go @@ -4,13 +4,14 @@ import ( "bytes" "crypto/tls" "encoding/json" - "log" "strconv" "text/template" + log "github.com/sirupsen/logrus" + gomail "gopkg.in/mail.v2" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/envstore" - gomail "gopkg.in/mail.v2" ) // addEmailTemplate is used to add html template in email body @@ -46,7 +47,7 @@ func SendMail(to []string, Subject, bodyMessage string) error { d.TLSConfig = &tls.Config{InsecureSkipVerify: true} } if err := d.DialAndSend(m); err != nil { - log.Printf("smtp error: %s", err) + log.Debug("SMTP Failed: ", err) return err } return nil diff --git a/server/email/invite_email.go b/server/email/invite_email.go index bdebd81..8689353 100644 --- a/server/email/invite_email.go +++ b/server/email/invite_email.go @@ -1,7 +1,7 @@ package email import ( - "log" + log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/envstore" @@ -107,7 +107,7 @@ func InviteEmail(toEmail, token, verificationURL, redirectURI string) error { err := SendMail(Receiver, Subject, message) if err != nil { - log.Println("error sending email:", err) + log.Warn("error sending email: ", err) } return err } diff --git a/server/email/verification_email.go b/server/email/verification_email.go index c373151..dd73657 100644 --- a/server/email/verification_email.go +++ b/server/email/verification_email.go @@ -1,7 +1,7 @@ package email import ( - "log" + log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/envstore" @@ -107,7 +107,7 @@ func SendVerificationMail(toEmail, token, hostname string) error { err := SendMail(Receiver, Subject, message) if err != nil { - log.Println("error sending email:", err) + log.Warn("error sending email: ", err) } return err } diff --git a/server/env/env.go b/server/env/env.go index 2972cf8..abf9b53 100644 --- a/server/env/env.go +++ b/server/env/env.go @@ -2,17 +2,17 @@ package env import ( "errors" - "log" "os" "strings" + "github.com/google/uuid" + "github.com/joho/godotenv" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/crypto" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/utils" - "github.com/gin-gonic/gin" - "github.com/google/uuid" - "github.com/joho/godotenv" ) // InitRequiredEnv to initialize EnvData and through error if required env are not present @@ -29,10 +29,11 @@ func InitRequiredEnv() error { if envstore.ARG_ENV_FILE != nil && *envstore.ARG_ENV_FILE != "" { envPath = *envstore.ARG_ENV_FILE } + log.Info("env path: ", envPath) err := godotenv.Load(envPath) if err != nil { - log.Printf("using OS env instead of %s file", envPath) + log.Info("using OS env instead of %s file", envPath) } dbURL := os.Getenv(constants.EnvKeyDatabaseURL) @@ -52,6 +53,7 @@ func InitRequiredEnv() error { } if dbType == "" { + log.Debug("DATABASE_TYPE is not set") return errors.New("invalid database type. DATABASE_TYPE is empty") } } @@ -62,6 +64,7 @@ func InitRequiredEnv() error { } if dbURL == "" && dbPort == "" && dbHost == "" && dbUsername == "" && dbPassword == "" { + log.Debug("DATABASE_URL is not set") return errors.New("invalid database url. DATABASE_URL is required") } } @@ -91,7 +94,7 @@ func InitRequiredEnv() error { func InitAllEnv() error { envData, err := GetEnvData() if err != nil { - log.Println("No env data found in db, using local clone of env data") + log.Info("No env data found in db, using local clone of env data") // get clone of current store envData = envstore.EnvStoreObj.GetEnvStoreClone() } @@ -118,7 +121,6 @@ func InitAllEnv() error { if envData.StringEnv[constants.EnvKeyEnv] == "production" { envData.BoolEnv[constants.EnvKeyIsProd] = true - gin.SetMode(gin.ReleaseMode) } else { envData.BoolEnv[constants.EnvKeyIsProd] = false } @@ -179,6 +181,7 @@ func InitAllEnv() error { } else { algo = envData.StringEnv[constants.EnvKeyJwtType] if !crypto.IsHMACA(algo) && !crypto.IsRSA(algo) && !crypto.IsECDSA(algo) { + log.Debug("Invalid JWT Algorithm") return errors.New("invalid JWT_TYPE") } } @@ -384,6 +387,7 @@ func InitAllEnv() error { } if len(roles) > 0 && len(defaultRoles) == 0 && len(defaultRolesEnv) > 0 { + log.Debug("Default roles not found in roles list. It can be one from ROLES only") return errors.New(`invalid DEFAULT_ROLE environment variable. It can be one from give ROLES environment variable value`) } diff --git a/server/env/persist_env.go b/server/env/persist_env.go index 82283d7..9b3c23e 100644 --- a/server/env/persist_env.go +++ b/server/env/persist_env.go @@ -2,12 +2,12 @@ package env import ( "encoding/json" - "log" "os" "strconv" "strings" "github.com/google/uuid" + log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/crypto" @@ -23,12 +23,14 @@ func GetEnvData() (envstore.Store, error) { env, err := db.Provider.GetEnv() // config not found in db if err != nil { + log.Debug("Error while getting env data from db: ", err) return result, err } encryptionKey := env.Hash decryptedEncryptionKey, err := crypto.DecryptB64(encryptionKey) if err != nil { + log.Debug("Error while decrypting encryption key: ", err) return result, err } @@ -36,16 +38,19 @@ func GetEnvData() (envstore.Store, error) { b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData) if err != nil { + log.Debug("Error while decrypting env data from B64: ", err) return result, err } decryptedConfigs, err := crypto.DecryptAESEnv([]byte(b64DecryptedConfig)) if err != nil { + log.Debug("Error while decrypting env data from AES: ", err) return result, err } err = json.Unmarshal(decryptedConfigs, &result) if err != nil { + log.Debug("Error while unmarshalling env data: ", err) return result, err } @@ -64,6 +69,7 @@ func PersistEnv() error { encryptedConfig, err := crypto.EncryptEnvData(envstore.EnvStoreObj.GetEnvStoreClone()) if err != nil { + log.Debug("Error while encrypting env data: ", err) return err } @@ -74,6 +80,7 @@ func PersistEnv() error { env, err = db.Provider.AddEnv(env) if err != nil { + log.Debug("Error while persisting env data to db: ", err) return err } } else { @@ -82,6 +89,7 @@ func PersistEnv() error { encryptionKey := env.Hash decryptedEncryptionKey, err := crypto.DecryptB64(encryptionKey) if err != nil { + log.Debug("Error while decrypting encryption key: ", err) return err } @@ -89,11 +97,13 @@ func PersistEnv() error { b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData) if err != nil { + log.Debug("Error while decrypting env data from B64: ", err) return err } decryptedConfigs, err := crypto.DecryptAESEnv([]byte(b64DecryptedConfig)) if err != nil { + log.Debug("Error while decrypting env data from AES: ", err) return err } @@ -102,6 +112,7 @@ func PersistEnv() error { err = json.Unmarshal(decryptedConfigs, &storeData) if err != nil { + log.Debug("Error while unmarshalling env data: ", err) return err } @@ -169,6 +180,7 @@ func PersistEnv() error { envstore.EnvStoreObj.UpdateEnvStore(storeData) jwk, err := crypto.GenerateJWKBasedOnEnv() if err != nil { + log.Debug("Error while generating JWK: ", err) return err } // updating jwk @@ -177,13 +189,14 @@ func PersistEnv() error { if hasChanged { encryptedConfig, err := crypto.EncryptEnvData(storeData) if err != nil { + log.Debug("Error while encrypting env data: ", err) return err } env.EnvData = encryptedConfig _, err = db.Provider.UpdateEnv(env) if err != nil { - log.Println("error updating config:", err) + log.Debug("Failed to Update Config: ", err) return err } } diff --git a/server/envstore/store.go b/server/envstore/store.go index e473615..d2f5487 100644 --- a/server/envstore/store.go +++ b/server/envstore/store.go @@ -13,6 +13,8 @@ var ( ARG_DB_TYPE *string // ARG_ENV_FILE is the cli arg variable for the env file ARG_ENV_FILE *string + // ARG_LOG_LEVEL is the cli arg variable for the log level + ARG_LOG_LEVEL *string ) // Store data structure diff --git a/server/go.mod b/server/go.mod index 7c341f5..be8365e 100644 --- a/server/go.mod +++ b/server/go.mod @@ -20,6 +20,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f + github.com/sirupsen/logrus v1.8.1 // indirect github.com/stretchr/testify v1.7.0 github.com/ugorji/go v1.2.6 // indirect github.com/vektah/gqlparser/v2 v2.2.0 diff --git a/server/go.sum b/server/go.sum index e386cbd..9392d6f 100644 --- a/server/go.sum +++ b/server/go.sum @@ -331,6 +331,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= diff --git a/server/handlers/app.go b/server/handlers/app.go index 9300eda..d855db7 100644 --- a/server/handlers/app.go +++ b/server/handlers/app.go @@ -1,14 +1,15 @@ package handlers import ( - "log" "net/http" "strings" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/utils" - "github.com/gin-gonic/gin" ) // State is the struct that holds authorizer url and redirect url @@ -23,6 +24,7 @@ func AppHandler() gin.HandlerFunc { return func(c *gin.Context) { hostname := utils.GetHost(c) if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableLoginPage) { + log.Debug("Login page is disabled") c.JSON(400, gin.H{"error": "login page is not enabled"}) return } @@ -43,6 +45,7 @@ func AppHandler() gin.HandlerFunc { } else { // validate redirect url with allowed origins if !utils.IsValidOrigin(redirect_uri) { + log.Debug("Invalid redirect_uri") c.JSON(400, gin.H{"error": "invalid redirect url"}) return } @@ -52,7 +55,7 @@ func AppHandler() gin.HandlerFunc { if pusher := c.Writer.Pusher(); pusher != nil { // use pusher.Push() to do server push if err := pusher.Push("/app/build/bundle.js", nil); err != nil { - log.Printf("Failed to push: %v", err) + log.Debug("Failed to push file path: ", err) } } c.HTML(http.StatusOK, "app.tmpl", gin.H{ diff --git a/server/handlers/authorize.go b/server/handlers/authorize.go index 572ebae..d8d6016 100644 --- a/server/handlers/authorize.go +++ b/server/handlers/authorize.go @@ -6,14 +6,16 @@ import ( "strings" "time" + "github.com/gin-gonic/gin" + "github.com/google/uuid" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/token" - "github.com/gin-gonic/gin" - "github.com/google/uuid" ) // AuthorizeHandler is the handler for the /authorize route @@ -48,6 +50,7 @@ func AuthorizeHandler() gin.HandlerFunc { } if responseMode != "query" && responseMode != "web_message" { + log.Debug("Invalid response_mode: ", responseMode) gc.JSON(400, gin.H{"error": "invalid response mode"}) } @@ -63,6 +66,7 @@ func AuthorizeHandler() gin.HandlerFunc { if isQuery { gc.Redirect(http.StatusFound, loginURL) } else { + log.Debug("Failed to get client_id: ", clientID) gc.HTML(http.StatusOK, template, gin.H{ "target_origin": redirectURI, "authorization_response": map[string]interface{}{ @@ -80,6 +84,7 @@ func AuthorizeHandler() gin.HandlerFunc { if isQuery { gc.Redirect(http.StatusFound, loginURL) } else { + log.Debug("Invalid client_id: ", clientID) gc.HTML(http.StatusOK, template, gin.H{ "target_origin": redirectURI, "authorization_response": map[string]interface{}{ @@ -97,6 +102,7 @@ func AuthorizeHandler() gin.HandlerFunc { if isQuery { gc.Redirect(http.StatusFound, loginURL) } else { + log.Debug("Failed to get state: ", state) gc.HTML(http.StatusOK, template, gin.H{ "target_origin": redirectURI, "authorization_response": map[string]interface{}{ @@ -121,6 +127,7 @@ func AuthorizeHandler() gin.HandlerFunc { if isQuery { gc.Redirect(http.StatusFound, loginURL) } else { + log.Debug("Invalid response_type: ", responseType) gc.HTML(http.StatusOK, template, gin.H{ "target_origin": redirectURI, "authorization_response": map[string]interface{}{ @@ -139,6 +146,7 @@ func AuthorizeHandler() gin.HandlerFunc { if isQuery { gc.Redirect(http.StatusFound, loginURL) } else { + log.Debug("Failed to get code_challenge: ", codeChallenge) gc.HTML(http.StatusBadRequest, template, gin.H{ "target_origin": redirectURI, "authorization_response": map[string]interface{}{ diff --git a/server/handlers/jwks.go b/server/handlers/jwks.go index cbcec38..2e13dc2 100644 --- a/server/handlers/jwks.go +++ b/server/handlers/jwks.go @@ -3,9 +3,11 @@ package handlers import ( "encoding/json" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/envstore" - "github.com/gin-gonic/gin" ) func JWKsHandler() gin.HandlerFunc { @@ -14,6 +16,7 @@ func JWKsHandler() gin.HandlerFunc { jwk := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJWK) err := json.Unmarshal([]byte(jwk), &data) if err != nil { + log.Debug("Failed to parse JWK: ", err) c.JSON(500, gin.H{ "error": err.Error(), }) diff --git a/server/handlers/logout.go b/server/handlers/logout.go index 7c7b756..66bc498 100644 --- a/server/handlers/logout.go +++ b/server/handlers/logout.go @@ -4,10 +4,12 @@ import ( "net/http" "strings" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/crypto" "github.com/authorizerdev/authorizer/server/sessionstore" - "github.com/gin-gonic/gin" ) // Handler to logout user @@ -17,6 +19,7 @@ func LogoutHandler() gin.HandlerFunc { // get fingerprint hash fingerprintHash, err := cookie.GetSession(gc) if err != nil { + log.Debug("Failed to get session: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) @@ -25,6 +28,7 @@ func LogoutHandler() gin.HandlerFunc { decryptedFingerPrint, err := crypto.DecryptAES(fingerprintHash) if err != nil { + log.Debug("Failed to decrypt fingerprint: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) diff --git a/server/handlers/oauth_callback.go b/server/handlers/oauth_callback.go index 3fdf7f6..07347c7 100644 --- a/server/handlers/oauth_callback.go +++ b/server/handlers/oauth_callback.go @@ -5,12 +5,16 @@ import ( "encoding/json" "fmt" "io/ioutil" - "log" "net/http" "strconv" "strings" "time" + "github.com/coreos/go-oidc/v3/oidc" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "golang.org/x/oauth2" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/db" @@ -20,9 +24,6 @@ import ( "github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" - "github.com/coreos/go-oidc/v3/oidc" - "github.com/gin-gonic/gin" - "golang.org/x/oauth2" ) // OAuthCallbackHandler handles the OAuth callback for various oauth providers @@ -33,6 +34,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { sessionState := sessionstore.GetState(state) if sessionState == "" { + log.Debug("Invalid oauth state: ", state) c.JSON(400, gin.H{"error": "invalid oauth state"}) } sessionstore.GetState(state) @@ -40,6 +42,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { sessionSplit := strings.Split(state, "___") if len(sessionSplit) < 3 { + log.Debug("Unable to get redirect url from state: ", state) c.JSON(400, gin.H{"error": "invalid redirect url"}) return } @@ -60,18 +63,22 @@ func OAuthCallbackHandler() gin.HandlerFunc { case constants.SignupMethodFacebook: user, err = processFacebookUserInfo(code) default: + log.Info("Invalid oauth provider") err = fmt.Errorf(`invalid oauth provider`) } if err != nil { + log.Debug("Failed to process user info: ", err) c.JSON(400, gin.H{"error": err.Error()}) return } existingUser, err := db.Provider.GetUserByEmail(user.Email) + log := log.WithField("user", user.Email) if err != nil { if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp) { + log.Debug("Failed to signup as disabled") c.JSON(400, gin.H{"error": "signup is disabled for this instance"}) return } @@ -86,6 +93,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { } if hasProtectedRole { + log.Debug("Signup is not allowed with protected roles:", inputRoles) c.JSON(400, gin.H{"error": "invalid role"}) return } @@ -96,6 +104,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { user, _ = db.Provider.AddUser(user) } else { if user.RevokedTimestamp != nil { + log.Debug("User access revoked at: ", user.RevokedTimestamp) c.JSON(400, gin.H{"error": "user access has been revoked"}) } @@ -137,6 +146,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { } if hasProtectedRole { + log.Debug("Invalid role. User is using protected unassigned role") c.JSON(400, gin.H{"error": "invalid role"}) return } else { @@ -148,6 +158,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { user, err = db.Provider.UpdateUser(user) if err != nil { + log.Debug("Failed to update user: ", err) c.JSON(500, gin.H{"error": err.Error()}) return } @@ -155,6 +166,7 @@ func OAuthCallbackHandler() gin.HandlerFunc { authToken, err := token.CreateAuthToken(c, user, inputRoles, scopes) if err != nil { + log.Debug("Failed to create auth token: ", err) c.JSON(500, gin.H{"error": err.Error()}) } @@ -194,6 +206,7 @@ func processGoogleUserInfo(code string) (models.User, error) { ctx := context.Background() oauth2Token, err := oauth.OAuthProviders.GoogleConfig.Exchange(ctx, code) if err != nil { + log.Debug("Failed to exchange code for token: ", err) return user, fmt.Errorf("invalid google exchange code: %s", err.Error()) } @@ -202,16 +215,19 @@ func processGoogleUserInfo(code string) (models.User, error) { // Extract the ID Token from OAuth2 token. rawIDToken, ok := oauth2Token.Extra("id_token").(string) if !ok { + log.Debug("Failed to extract ID Token from OAuth2 token") return user, fmt.Errorf("unable to extract id_token") } // Parse and verify ID Token payload. idToken, err := verifier.Verify(ctx, rawIDToken) if err != nil { + log.Debug("Failed to verify ID Token: ", err) return user, fmt.Errorf("unable to verify id_token: %s", err.Error()) } if err := idToken.Claims(&user); err != nil { + log.Debug("Failed to parse ID Token claims: ", err) return user, fmt.Errorf("unable to extract claims") } @@ -222,11 +238,13 @@ func processGithubUserInfo(code string) (models.User, error) { user := models.User{} token, err := oauth.OAuthProviders.GithubConfig.Exchange(oauth2.NoContext, code) if err != nil { + log.Debug("Failed to exchange code for token: ", err) return user, fmt.Errorf("invalid github exchange code: %s", err.Error()) } client := http.Client{} req, err := http.NewRequest("GET", constants.GithubUserInfoURL, nil) if err != nil { + log.Debug("Failed to create github user info request: ", err) return user, fmt.Errorf("error creating github user info request: %s", err.Error()) } req.Header = http.Header{ @@ -235,12 +253,14 @@ func processGithubUserInfo(code string) (models.User, error) { response, err := client.Do(req) if err != nil { + log.Debug("Failed to request github user info: ", err) return user, err } defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) if err != nil { + log.Debug("Failed to read github user info response body: ", err) return user, fmt.Errorf("failed to read github response body: %s", err.Error()) } @@ -273,23 +293,26 @@ func processFacebookUserInfo(code string) (models.User, error) { user := models.User{} token, err := oauth.OAuthProviders.FacebookConfig.Exchange(oauth2.NoContext, code) if err != nil { + log.Debug("Invalid facebook exchange code: ", err) return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error()) } client := http.Client{} req, err := http.NewRequest("GET", constants.FacebookUserInfoURL+token.AccessToken, nil) if err != nil { + log.Debug("Error creating facebook user info request: ", err) return user, fmt.Errorf("error creating facebook user info request: %s", err.Error()) } response, err := client.Do(req) if err != nil { - log.Println("error processing facebook user info:", err) + log.Debug("Failed to process facebook user: ", err) return user, err } defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) if err != nil { + log.Debug("Failed to read facebook response: ", err) return user, fmt.Errorf("failed to read facebook response body: %s", err.Error()) } diff --git a/server/handlers/oauth_login.go b/server/handlers/oauth_login.go index f2683a8..3dc3351 100644 --- a/server/handlers/oauth_login.go +++ b/server/handlers/oauth_login.go @@ -4,12 +4,14 @@ import ( "net/http" "strings" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/oauth" "github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/utils" - "github.com/gin-gonic/gin" ) // OAuthLoginHandler set host in the oauth state that is useful for redirecting to oauth_callback @@ -26,6 +28,7 @@ func OAuthLoginHandler() gin.HandlerFunc { scopeString := strings.TrimSpace(c.Query("scope")) if redirectURI == "" { + log.Debug("redirect_uri is empty") c.JSON(400, gin.H{ "error": "invalid redirect uri", }) @@ -33,6 +36,7 @@ func OAuthLoginHandler() gin.HandlerFunc { } if state == "" { + log.Debug("state is empty") c.JSON(400, gin.H{ "error": "invalid state", }) @@ -53,6 +57,7 @@ func OAuthLoginHandler() gin.HandlerFunc { // use protected roles verification for admin login only. // though if not associated with user, it will be rejected from oauth_callback if !utils.IsValidRoles(rolesSplit, append([]string{}, append(envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyRoles), envstore.EnvStoreObj.GetSliceStoreEnvVariable(constants.EnvKeyProtectedRoles)...)...)) { + log.Debug("Invalid roles: ", roles) c.JSON(400, gin.H{ "error": "invalid role", }) @@ -69,6 +74,7 @@ func OAuthLoginHandler() gin.HandlerFunc { switch provider { case constants.SignupMethodGoogle: if oauth.OAuthProviders.GoogleConfig == nil { + log.Debug("Google OAuth provider is not configured") isProviderConfigured = false break } @@ -79,6 +85,7 @@ func OAuthLoginHandler() gin.HandlerFunc { c.Redirect(http.StatusTemporaryRedirect, url) case constants.SignupMethodGithub: if oauth.OAuthProviders.GithubConfig == nil { + log.Debug("Github OAuth provider is not configured") isProviderConfigured = false break } @@ -88,6 +95,7 @@ func OAuthLoginHandler() gin.HandlerFunc { c.Redirect(http.StatusTemporaryRedirect, url) case constants.SignupMethodFacebook: if oauth.OAuthProviders.FacebookConfig == nil { + log.Debug("Facebook OAuth provider is not configured") isProviderConfigured = false break } @@ -96,6 +104,7 @@ func OAuthLoginHandler() gin.HandlerFunc { url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) default: + log.Debug("Invalid oauth provider: ", provider) c.JSON(422, gin.H{ "message": "Invalid oauth provider", }) diff --git a/server/handlers/revoke.go b/server/handlers/revoke.go index 6dc79db..f6d2bfc 100644 --- a/server/handlers/revoke.go +++ b/server/handlers/revoke.go @@ -4,10 +4,12 @@ import ( "net/http" "strings" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/sessionstore" - "github.com/gin-gonic/gin" ) // Revoke handler to revoke refresh token @@ -15,6 +17,7 @@ func RevokeHandler() gin.HandlerFunc { return func(gc *gin.Context) { var reqBody map[string]string if err := gc.BindJSON(&reqBody); err != nil { + log.Debug("Error binding JSON: ", err) gc.JSON(http.StatusBadRequest, gin.H{ "error": "error_binding_json", "error_description": err.Error(), @@ -26,6 +29,7 @@ func RevokeHandler() gin.HandlerFunc { clientID := strings.TrimSpace(reqBody["client_id"]) if clientID == "" { + log.Debug("Client ID is empty") gc.JSON(http.StatusBadRequest, gin.H{ "error": "client_id_required", "error_description": "The client id is required", @@ -34,6 +38,7 @@ func RevokeHandler() gin.HandlerFunc { } if clientID != envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID) { + log.Debug("Client ID is invalid: ", clientID) gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_client_id", "error_description": "The client id is invalid", diff --git a/server/handlers/token.go b/server/handlers/token.go index 516aafe..895a672 100644 --- a/server/handlers/token.go +++ b/server/handlers/token.go @@ -7,13 +7,15 @@ import ( "strings" "time" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/token" - "github.com/gin-gonic/gin" ) // TokenHandler to handle /oauth/token requests @@ -22,6 +24,7 @@ func TokenHandler() gin.HandlerFunc { return func(gc *gin.Context) { var reqBody map[string]string if err := gc.BindJSON(&reqBody); err != nil { + log.Debug("Error binding JSON: ", err) gc.JSON(http.StatusBadRequest, gin.H{ "error": "error_binding_json", "error_description": err.Error(), @@ -43,6 +46,7 @@ func TokenHandler() gin.HandlerFunc { isAuthorizationCodeGrant := grantType == "authorization_code" if !isRefreshTokenGrant && !isAuthorizationCodeGrant { + log.Debug("Invalid grant type: ", grantType) gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_grant_type", "error_description": "grant_type is invalid", @@ -50,6 +54,7 @@ func TokenHandler() gin.HandlerFunc { } if clientID == "" { + log.Debug("Client ID is empty") gc.JSON(http.StatusBadRequest, gin.H{ "error": "client_id_required", "error_description": "The client id is required", @@ -58,6 +63,7 @@ func TokenHandler() gin.HandlerFunc { } if clientID != envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyClientID) { + log.Debug("Client ID is invalid: ", clientID) gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_client_id", "error_description": "The client id is invalid", @@ -70,6 +76,7 @@ func TokenHandler() gin.HandlerFunc { if isAuthorizationCodeGrant { if codeVerifier == "" { + log.Debug("Code verifier is empty") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_code_verifier", "error_description": "The code verifier is required", @@ -78,6 +85,7 @@ func TokenHandler() gin.HandlerFunc { } if code == "" { + log.Debug("Code is empty") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_code", "error_description": "The code is required", @@ -92,6 +100,7 @@ func TokenHandler() gin.HandlerFunc { encryptedCode = strings.ReplaceAll(encryptedCode, "=", "") sessionData := sessionstore.GetState(encryptedCode) if sessionData == "" { + log.Debug("Session data is empty") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_code_verifier", "error_description": "The code verifier is invalid", @@ -104,6 +113,7 @@ func TokenHandler() gin.HandlerFunc { sessionDataSplit := strings.Split(sessionData, "@") if sessionDataSplit[0] != code { + log.Debug("Invalid code verifier. Unable to split session data") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_code_verifier", "error_description": "The code verifier is invalid", @@ -114,6 +124,7 @@ func TokenHandler() gin.HandlerFunc { // validate session claims, err := token.ValidateBrowserSession(gc, sessionDataSplit[1]) if err != nil { + log.Debug("Error validating session: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ "error": "unauthorized", "error_description": "Invalid session data", @@ -128,6 +139,7 @@ func TokenHandler() gin.HandlerFunc { } else { // validate refresh token if refreshToken == "" { + log.Debug("Refresh token is empty") gc.JSON(http.StatusBadRequest, gin.H{ "error": "invalid_refresh_token", "error_description": "The refresh token is invalid", @@ -136,6 +148,7 @@ func TokenHandler() gin.HandlerFunc { claims, err := token.ValidateRefreshToken(gc, refreshToken) if err != nil { + log.Debug("Error validating refresh token: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ "error": "unauthorized", "error_description": err.Error(), @@ -156,6 +169,7 @@ func TokenHandler() gin.HandlerFunc { user, err := db.Provider.GetUserByID(userID) if err != nil { + log.Debug("Error getting user: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ "error": "unauthorized", "error_description": "User not found", @@ -165,6 +179,7 @@ func TokenHandler() gin.HandlerFunc { authToken, err := token.CreateAuthToken(gc, user, roles, scope) if err != nil { + log.Debug("Error creating auth token: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ "error": "unauthorized", "error_description": "User not found", diff --git a/server/handlers/userinfo.go b/server/handlers/userinfo.go index 9e9c6f5..3bc0164 100644 --- a/server/handlers/userinfo.go +++ b/server/handlers/userinfo.go @@ -3,15 +3,18 @@ package handlers import ( "net/http" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/token" - "github.com/gin-gonic/gin" ) func UserInfoHandler() gin.HandlerFunc { return func(gc *gin.Context) { accessToken, err := token.GetAccessToken(gc) if err != nil { + log.Debug("Error getting access token: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) @@ -20,6 +23,7 @@ func UserInfoHandler() gin.HandlerFunc { claims, err := token.ValidateAccessToken(gc, accessToken) if err != nil { + log.Debug("Error validating access token: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) @@ -29,6 +33,7 @@ func UserInfoHandler() gin.HandlerFunc { userID := claims["sub"].(string) user, err := db.Provider.GetUserByID(userID) if err != nil { + log.Debug("Error getting user: ", err) gc.JSON(http.StatusUnauthorized, gin.H{ "error": err.Error(), }) diff --git a/server/handlers/verify_email.go b/server/handlers/verify_email.go index 319537d..0d34b7d 100644 --- a/server/handlers/verify_email.go +++ b/server/handlers/verify_email.go @@ -6,13 +6,15 @@ import ( "strings" "time" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/sessionstore" "github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/utils" - "github.com/gin-gonic/gin" ) // VerifyEmailHandler handles the verify email route. @@ -24,12 +26,14 @@ func VerifyEmailHandler() gin.HandlerFunc { } tokenInQuery := c.Query("token") if tokenInQuery == "" { + log.Debug("Token is empty") c.JSON(400, errorRes) return } verificationRequest, err := db.Provider.GetVerificationRequestByToken(tokenInQuery) if err != nil { + log.Debug("Error getting verification request: ", err) errorRes["error_description"] = err.Error() c.JSON(400, errorRes) return @@ -39,6 +43,7 @@ func VerifyEmailHandler() gin.HandlerFunc { hostname := utils.GetHost(c) claim, err := token.ParseJWTToken(tokenInQuery, hostname, verificationRequest.Nonce, verificationRequest.Email) if err != nil { + log.Debug("Error parsing token: ", err) errorRes["error_description"] = err.Error() c.JSON(400, errorRes) return @@ -46,6 +51,7 @@ func VerifyEmailHandler() gin.HandlerFunc { user, err := db.Provider.GetUserByEmail(claim["sub"].(string)) if err != nil { + log.Debug("Error getting user: ", err) errorRes["error_description"] = err.Error() c.JSON(400, errorRes) return @@ -79,6 +85,7 @@ func VerifyEmailHandler() gin.HandlerFunc { } authToken, err := token.CreateAuthToken(c, user, roles, scope) if err != nil { + log.Debug("Error creating auth token: ", err) errorRes["error_description"] = err.Error() c.JSON(500, errorRes) return diff --git a/server/main.go b/server/main.go index 9a21b29..347dbae 100644 --- a/server/main.go +++ b/server/main.go @@ -2,7 +2,9 @@ package main import ( "flag" - "log" + + "github.com/sirupsen/logrus" + log "github.com/sirupsen/logrus" "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/db" @@ -15,25 +17,63 @@ import ( var VERSION string +type LogUTCFormatter struct { + log.Formatter +} + +func (u LogUTCFormatter) Format(e *log.Entry) ([]byte, error) { + e.Time = e.Time.UTC() + return u.Formatter.Format(e) +} + func main() { envstore.ARG_DB_URL = flag.String("database_url", "", "Database connection string") envstore.ARG_DB_TYPE = flag.String("database_type", "", "Database type, possible values are postgres,mysql,sqlite") envstore.ARG_ENV_FILE = flag.String("env_file", "", "Env file path") + envstore.ARG_LOG_LEVEL = flag.String("log_level", "info", "Log level, possible values are debug,info,warn,error,fatal,panic") flag.Parse() - log.Println("=> version:", VERSION) + // global log level + logrus.SetFormatter(LogUTCFormatter{&logrus.JSONFormatter{}}) + logrus.SetReportCaller(true) + + // log instance for gin server + log := logrus.New() + log.SetFormatter(LogUTCFormatter{&logrus.JSONFormatter{}}) + log.SetReportCaller(true) + + var logLevel logrus.Level + switch *envstore.ARG_LOG_LEVEL { + case "debug": + logLevel = logrus.DebugLevel + case "info": + logLevel = logrus.InfoLevel + case "warn": + logLevel = logrus.WarnLevel + case "error": + logLevel = logrus.ErrorLevel + case "fatal": + logLevel = logrus.FatalLevel + case "panic": + logLevel = logrus.PanicLevel + default: + logLevel = logrus.InfoLevel + } + logrus.SetLevel(logLevel) + log.SetLevel(logLevel) + constants.VERSION = VERSION // initialize required envs (mainly db & env file path) err := env.InitRequiredEnv() if err != nil { - log.Fatal("Error while initializing required envs:", err) + log.Fatal("Error while initializing required envs: ", err) } // initialize db provider err = db.InitDB() if err != nil { - log.Fatalln("Error while initializing db:", err) + log.Fatalln("Error while initializing db: ", err) } // initialize all envs @@ -46,21 +86,22 @@ func main() { // persist all envs err = env.PersistEnv() if err != nil { - log.Fatalln("Error while persisting env:", err) + log.Fatalln("Error while persisting env: ", err) } // initialize session store (redis or in-memory based on env) err = sessionstore.InitSession() if err != nil { - log.Fatalln("Error while initializing session store:", err) + log.Fatalln("Error while initializing session store: ", err) } // initialize oauth providers based on env err = oauth.InitOAuth() if err != nil { - log.Fatalln("Error while initializing oauth:", err) + log.Fatalln("Error while initializing oauth: ", err) } - router := routes.InitRouter() + router := routes.InitRouter(log) + log.Info("Starting Authorizer: ", VERSION) router.Run(":" + envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyPort)) } diff --git a/server/middlewares/log.go b/server/middlewares/log.go new file mode 100644 index 0000000..357b4b2 --- /dev/null +++ b/server/middlewares/log.go @@ -0,0 +1,78 @@ +package middlewares + +import ( + "fmt" + "math" + "net/http" + "os" + "time" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" +) + +var timeFormat = "02/Jan/2006:15:04:05 -0700" + +// Logger is the logrus logger handler +func Logger(logger logrus.FieldLogger, notLogged ...string) gin.HandlerFunc { + hostname, err := os.Hostname() + if err != nil { + hostname = "unknown" + } + + var skip map[string]struct{} + + if length := len(notLogged); length > 0 { + skip = make(map[string]struct{}, length) + + for _, p := range notLogged { + skip[p] = struct{}{} + } + } + + return func(c *gin.Context) { + // other handler can change c.Path so: + path := c.Request.URL.Path + start := time.Now() + c.Next() + stop := time.Since(start) + latency := int(math.Ceil(float64(stop.Nanoseconds()) / 1000000.0)) + statusCode := c.Writer.Status() + clientIP := c.ClientIP() + clientUserAgent := c.Request.UserAgent() + referer := c.Request.Referer() + dataLength := c.Writer.Size() + if dataLength < 0 { + dataLength = 0 + } + + if _, ok := skip[path]; ok { + return + } + + entry := logger.WithFields(logrus.Fields{ + "hostname": hostname, + "statusCode": statusCode, + "latency": latency, // time to process + "clientIP": clientIP, + "method": c.Request.Method, + "path": path, + "referer": referer, + "dataLength": dataLength, + "userAgent": clientUserAgent, + }) + + if len(c.Errors) > 0 { + entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String()) + } else { + msg := fmt.Sprintf("%s - %s [%s] \"%s %s\" %d %d \"%s\" \"%s\" (%dms)", clientIP, hostname, time.Now().Format(timeFormat), c.Request.Method, path, statusCode, dataLength, referer, clientUserAgent, latency) + if statusCode >= http.StatusInternalServerError { + entry.Error(msg) + } else if statusCode >= http.StatusBadRequest { + entry.Warn(msg) + } else { + entry.Info(msg) + } + } + } +} 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..7de2421 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..64befe0 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..2952844 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..399e95d 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 164c413..4fadbfe 100644 --- a/server/resolvers/delete_user.go +++ b/server/resolvers/delete_user.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" @@ -14,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 } @@ -33,7 +42,7 @@ func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*mod err = db.Provider.DeleteUser(user) if err != nil { - log.Println("error 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..0d9f148 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..c1ddcff 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..ec7049e 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,28 +20,38 @@ 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: ", params.Email) return res, fmt.Errorf("invalid email") } + log := log.WithFields(log.Fields{ + "email": params.Email, + }) _, err = db.Provider.GetUserByEmail(params.Email) if err != nil { + log.Debug("User not found: ", err) return res, fmt.Errorf(`user with this email not found`) } hostname := utils.GetHost(gc) _, nonceHash, err := utils.GenerateNonce() if err != nil { + log.Debug("Failed to generate nonce: ", err) return res, err } redirectURL := utils.GetAppURL(gc) + "/reset-password" @@ -50,9 +61,10 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, 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: constants.VerificationTypeForgotPassword, ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), @@ -60,6 +72,10 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu 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.SendForgotPasswordMail(params.Email, verificationToken, hostname) diff --git a/server/resolvers/generate_jwt_keys.go b/server/resolvers/generate_jwt_keys.go index 6c4c9e5..8f0050e 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..30dc79a 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.Debugf("User with %s email not found, so inviting user", email) newEmails = append(newEmails, email) } else { - log.Println("%s user already exists. skipping.", email) + log.Debugf("User with %s email already exists, so not inviting user", email) } } 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.Debugf("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.Debugf("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..eda8c9d 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: ", params.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..9683237 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..d79fc46 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: ", params.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 at: ", user.RevokedTimestamp) 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..b76d3a6 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..6ae6f34 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..77f1c96 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..a7b6ab0 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..0698b64 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..b8cffce 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..be298f9 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..a7ddc49 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,29 +24,39 @@ 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 } // validate if all params are not empty if params.GivenName == nil && params.FamilyName == nil && params.Picture == nil && params.MiddleName == nil && params.Nickname == nil && params.OldPassword == nil && params.Email == nil && params.Birthdate == nil && params.Gender == nil && params.PhoneNumber == nil { + log.Debug("All params are empty") return res, fmt.Errorf("please enter at least one param to update") } 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 +94,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,22 +123,28 @@ 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) + + // check if valid email + if !utils.IsValidEmail(newEmail) { + log.Debug("Failed to validate new email: ", newEmail) + return res, fmt.Errorf("invalid new email address") + } // check if user with new email exists _, 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 +152,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 +170,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 +182,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..3628ba4 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("UserID is empty") + 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..5f24b2b 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..4733eb2 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..fe2f5f0 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..c19fdcc 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 } diff --git a/server/routes/routes.go b/server/routes/routes.go index afde5d8..4ce00f9 100644 --- a/server/routes/routes.go +++ b/server/routes/routes.go @@ -1,15 +1,19 @@ package routes import ( + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/handlers" "github.com/authorizerdev/authorizer/server/middlewares" - "github.com/gin-gonic/gin" ) // InitRouter initializes gin router -func InitRouter() *gin.Engine { - router := gin.Default() - // router.Use(location.Default()) +func InitRouter(log *logrus.Logger) *gin.Engine { + gin.SetMode(gin.ReleaseMode) + router := gin.New() + + router.Use(middlewares.Logger(log), gin.Recovery()) router.Use(middlewares.GinContextToContextMiddleware()) router.Use(middlewares.CORSMiddleware()) diff --git a/server/sessionstore/redis_store.go b/server/sessionstore/redis_store.go index 4fad694..6ade0fa 100644 --- a/server/sessionstore/redis_store.go +++ b/server/sessionstore/redis_store.go @@ -2,8 +2,9 @@ package sessionstore import ( "context" - "log" "strings" + + log "github.com/sirupsen/logrus" ) type RedisStore struct { @@ -15,7 +16,7 @@ type RedisStore struct { func (c *RedisStore) ClearStore() { err := c.store.Del(c.ctx, "authorizer_*").Err() if err != nil { - log.Fatalln("Error clearing redis store:", err) + log.Debug("Error clearing redis store: ", err) } } @@ -23,7 +24,7 @@ func (c *RedisStore) ClearStore() { func (c *RedisStore) GetUserSessions(userID string) map[string]string { data, err := c.store.HGetAll(c.ctx, "*").Result() if err != nil { - log.Println("error getting token from redis store:", err) + log.Debug("error getting token from redis store: ", err) } res := map[string]string{} @@ -44,7 +45,7 @@ func (c *RedisStore) DeleteAllUserSession(userId string) { if k == "token" { err := c.store.Del(c.ctx, v) if err != nil { - log.Println("Error deleting redis token:", err) + log.Debug("Error deleting redis token: ", err) } } } @@ -54,7 +55,7 @@ func (c *RedisStore) DeleteAllUserSession(userId string) { func (c *RedisStore) SetState(key, value string) { err := c.store.Set(c.ctx, "authorizer_"+key, value, 0).Err() if err != nil { - log.Fatalln("Error saving redis token:", err) + log.Debug("Error saving redis token: ", err) } } @@ -63,7 +64,7 @@ func (c *RedisStore) GetState(key string) string { state := "" state, err := c.store.Get(c.ctx, "authorizer_"+key).Result() if err != nil { - log.Println("error getting token from redis store:", err) + log.Debug("error getting token from redis store: ", err) } return state @@ -73,6 +74,6 @@ func (c *RedisStore) GetState(key string) string { func (c *RedisStore) RemoveState(key string) { err := c.store.Del(c.ctx, "authorizer_"+key).Err() if err != nil { - log.Fatalln("Error deleting redis token:", err) + log.Fatalln("Error deleting redis token: ", err) } } diff --git a/server/sessionstore/session.go b/server/sessionstore/session.go index 659ddaa..7626e8f 100644 --- a/server/sessionstore/session.go +++ b/server/sessionstore/session.go @@ -2,9 +2,10 @@ package sessionstore import ( "context" - "log" "strings" + log "github.com/sirupsen/logrus" + "github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/envstore" "github.com/go-redis/redis/v8" @@ -89,7 +90,7 @@ func RemoveState(key string) { // InitializeSessionStore initializes the SessionStoreObj based on environment variables func InitSession() error { if envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL) != "" { - log.Println("using redis store to save sessions") + log.Info("using redis store to save sessions") redisURL := envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL) redisURLHostPortsList := strings.Split(redisURL, ",") @@ -97,6 +98,7 @@ func InitSession() error { if len(redisURLHostPortsList) > 1 { opt, err := redis.ParseURL(redisURLHostPortsList[0]) if err != nil { + log.Debug("error parsing redis url: ", err) return err } urls := []string{opt.Addr} @@ -108,6 +110,7 @@ func InitSession() error { ctx := context.Background() _, err = rdb.Ping(ctx).Result() if err != nil { + log.Debug("error connecting to redis: ", err) return err } SessionStoreObj.RedisMemoryStoreObj = &RedisStore{ @@ -121,6 +124,7 @@ func InitSession() error { opt, err := redis.ParseURL(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL)) if err != nil { + log.Debug("error parsing redis url: ", err) return err } @@ -128,6 +132,7 @@ func InitSession() error { ctx := context.Background() _, err = rdb.Ping(ctx).Result() if err != nil { + log.Debug("error connecting to redis: ", err) return err } @@ -140,6 +145,7 @@ func InitSession() error { return nil } + log.Info("using in memory store to save sessions") // if redis url is not set use in memory store SessionStoreObj.InMemoryStoreObj = &InMemoryStore{ sessionStore: map[string]map[string]string{}, diff --git a/server/token/auth_token.go b/server/token/auth_token.go index 56d9e08..6f8930f 100644 --- a/server/token/auth_token.go +++ b/server/token/auth_token.go @@ -3,10 +3,11 @@ package token import ( "encoding/json" "fmt" - "log" "strings" "time" + log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt" "github.com/google/uuid" @@ -330,14 +331,13 @@ func CreateIDToken(user models.User, roles []string, hostname, nonce string) (st `, string(userBytes), string(claimBytes), accessTokenScript)) val, err := vm.Get("functionRes") - if err != nil { - log.Println("error getting custom access token script:", err) + log.Debug("error getting custom access token script: ", err) } else { extraPayload := make(map[string]interface{}) err = json.Unmarshal([]byte(fmt.Sprintf("%s", val)), &extraPayload) if err != nil { - log.Println("error converting accessTokenScript response to map:", err) + log.Debug("error converting accessTokenScript response to map: ", err) } else { for k, v := range extraPayload { customClaims[k] = v