diff --git a/controllers/userHttpController.go b/controllers/userHttpController.go index 7c56a2cb..cc180220 100644 --- a/controllers/userHttpController.go +++ b/controllers/userHttpController.go @@ -1,117 +1,117 @@ package controller import ( - "gopkg.in/go-playground/validator.v9" - "github.com/gravitl/netmaker/models" - "github.com/gravitl/netmaker/functions" - "github.com/gravitl/netmaker/mongoconn" - "golang.org/x/crypto/bcrypt" - "time" - "errors" - "strings" - "fmt" - "context" - "encoding/json" - "net/http" - "github.com/gorilla/mux" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo/options" - "go.mongodb.org/mongo-driver/mongo" -) + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + "time" + "github.com/gorilla/mux" + "github.com/gravitl/netmaker/functions" + "github.com/gravitl/netmaker/models" + "github.com/gravitl/netmaker/mongoconn" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "golang.org/x/crypto/bcrypt" + "gopkg.in/go-playground/validator.v9" +) func userHandlers(r *mux.Router) { - r.HandleFunc("/api/users/adm/hasadmin", hasAdmin).Methods("GET") - r.HandleFunc("/api/users/adm/createadmin", createAdmin).Methods("POST") - r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods("POST") - r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(updateUser))).Methods("PUT") - r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(deleteUser))).Methods("DELETE") - r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(getUser))).Methods("GET") + r.HandleFunc("/api/users/adm/hasadmin", hasAdmin).Methods("GET") + r.HandleFunc("/api/users/adm/createadmin", createAdmin).Methods("POST") + r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods("POST") + r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(updateUser))).Methods("PUT") + r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(deleteUser))).Methods("DELETE") + r.HandleFunc("/api/users/{username}", authorizeUser(http.HandlerFunc(getUser))).Methods("GET") } //Node authenticates using its password and retrieves a JWT for authorization. func authenticateUser(response http.ResponseWriter, request *http.Request) { - //Auth request consists of Mac Address and Password (from node that is authorizing - //in case of Master, auth is ignored and mac is set to "mastermac" - var authRequest models.UserAuthParams - var result models.User - var errorResponse = models.ErrorResponse{ - Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", - } - - decoder := json.NewDecoder(request.Body) - decoderErr := decoder.Decode(&authRequest) - defer request.Body.Close() - - if decoderErr != nil { - returnErrorResponse(response, request, errorResponse) - return - } else { - errorResponse.Code = http.StatusBadRequest - if authRequest.UserName == "" { - errorResponse.Message = "W1R3: Username can't be empty" - returnErrorResponse(response, request, errorResponse) - return - } else if authRequest.Password == "" { - errorResponse.Message = "W1R3: Password can't be empty" - returnErrorResponse(response, request, errorResponse) - return - } else { - - //Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved). - collection := mongoconn.Client.Database("netmaker").Collection("users") - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - var err = collection.FindOne(ctx, bson.M{ "username": authRequest.UserName }).Decode(&result) - - defer cancel() - - if err != nil { - errorResponse.Message = "W1R3: User " + authRequest.UserName + " not found." - returnErrorResponse(response, request, errorResponse) - return - } - - //compare password from request to stored password in database - //might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text... - //TODO: Consider a way of hashing the password client side before sending, or using certificates - err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password)) - if err != nil { - errorResponse = models.ErrorResponse{ - Code: http.StatusUnauthorized, Message: "W1R3: Wrong Password.", - } - returnErrorResponse(response, request, errorResponse) - return - } else { - //Create a new JWT for the node - tokenString, _ := functions.CreateUserJWT(authRequest.UserName, result.IsAdmin) - - if tokenString == "" { - returnErrorResponse(response, request, errorResponse) - return - } - - var successResponse = models.SuccessResponse{ - Code: http.StatusOK, - Message: "W1R3: Device " + authRequest.UserName + " Authorized", - Response: models.SuccessfulUserLoginResponse{ - AuthToken: tokenString, - UserName: authRequest.UserName, - }, - } - //Send back the JWT - successJSONResponse, jsonError := json.Marshal(successResponse) - - if jsonError != nil { - returnErrorResponse(response, request, errorResponse) - return - } - response.Header().Set("Content-Type", "application/json") - response.Write(successJSONResponse) - } + //Auth request consists of Mac Address and Password (from node that is authorizing + //in case of Master, auth is ignored and mac is set to "mastermac" + var authRequest models.UserAuthParams + var result models.User + var errorResponse = models.ErrorResponse{ + Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", + } + + decoder := json.NewDecoder(request.Body) + decoderErr := decoder.Decode(&authRequest) + defer request.Body.Close() + + if decoderErr != nil { + returnErrorResponse(response, request, errorResponse) + return + } else { + errorResponse.Code = http.StatusBadRequest + if authRequest.UserName == "" { + errorResponse.Message = "W1R3: Username can't be empty" + returnErrorResponse(response, request, errorResponse) + return + } else if authRequest.Password == "" { + errorResponse.Message = "W1R3: Password can't be empty" + returnErrorResponse(response, request, errorResponse) + return + } else { + + //Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved). + collection := mongoconn.Client.Database("netmaker").Collection("users") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + var err = collection.FindOne(ctx, bson.M{"username": authRequest.UserName}).Decode(&result) + + defer cancel() + + if err != nil { + errorResponse.Message = "W1R3: User " + authRequest.UserName + " not found." + returnErrorResponse(response, request, errorResponse) + return + } + + //compare password from request to stored password in database + //might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text... + //TODO: Consider a way of hashing the password client side before sending, or using certificates + err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password)) + if err != nil { + errorResponse = models.ErrorResponse{ + Code: http.StatusUnauthorized, Message: "W1R3: Wrong Password.", + } + returnErrorResponse(response, request, errorResponse) + return + } else { + //Create a new JWT for the node + tokenString, _ := functions.CreateUserJWT(authRequest.UserName, result.IsAdmin) + + if tokenString == "" { + returnErrorResponse(response, request, errorResponse) + return + } + + var successResponse = models.SuccessResponse{ + Code: http.StatusOK, + Message: "W1R3: Device " + authRequest.UserName + " Authorized", + Response: models.SuccessfulUserLoginResponse{ + AuthToken: tokenString, + UserName: authRequest.UserName, + }, + } + //Send back the JWT + successJSONResponse, jsonError := json.Marshal(successResponse) + + if jsonError != nil { + returnErrorResponse(response, request, errorResponse) + return + } + response.Header().Set("Content-Type", "application/json") + response.Write(successJSONResponse) + } + } } - } } //The middleware for most requests to the API @@ -122,30 +122,30 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) { //This is kind of a poor man's RBAC. There's probably a better/smarter way. //TODO: Consider better RBAC implementations func authorizeUser(next http.Handler) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { - var errorResponse = models.ErrorResponse{ - Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", - } + var errorResponse = models.ErrorResponse{ + Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", + } - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Content-Type", "application/json") //get the auth token bearerToken := r.Header.Get("Authorization") - var tokenSplit = strings.Split(bearerToken, " ") + var tokenSplit = strings.Split(bearerToken, " ") //I put this in in case the user doesn't put in a token at all (in which case it's empty) //There's probably a smarter way of handling this. - var authToken = "928rt238tghgwe@TY@$Y@#WQAEGB2FC#@HG#@$Hddd" + var authToken = "928rt238tghgwe@TY@$Y@#WQAEGB2FC#@HG#@$Hddd" - if len(tokenSplit) > 1 { - authToken = tokenSplit[1] - } else { - errorResponse = models.ErrorResponse{ - Code: http.StatusUnauthorized, Message: "W1R3: Missing Auth Token.", - } - returnErrorResponse(w, r, errorResponse) + if len(tokenSplit) > 1 { + authToken = tokenSplit[1] + } else { + errorResponse = models.ErrorResponse{ + Code: http.StatusUnauthorized, Message: "W1R3: Missing Auth Token.", + } + returnErrorResponse(w, r, errorResponse) return } @@ -156,10 +156,10 @@ func authorizeUser(next http.Handler) http.HandlerFunc { username, _, err := functions.VerifyUserToken(authToken) if err != nil { - errorResponse = models.ErrorResponse{ - Code: http.StatusUnauthorized, Message: "W1R3: Error Verifying Auth Token.", - } - returnErrorResponse(w, r, errorResponse) + errorResponse = models.ErrorResponse{ + Code: http.StatusUnauthorized, Message: "W1R3: Error Verifying Auth Token.", + } + returnErrorResponse(w, r, errorResponse) return } @@ -178,22 +178,22 @@ func authorizeUser(next http.Handler) http.HandlerFunc { } } -func HasAdmin() (bool, error){ +func HasAdmin() (bool, error) { - collection := mongoconn.Client.Database("netmaker").Collection("users") + collection := mongoconn.Client.Database("netmaker").Collection("users") - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - filter := bson.M{"isadmin": true} + filter := bson.M{"isadmin": true} - //Filtering out the ID field cuz Dillon doesn't like it. May want to filter out other fields in the future - var result bson.M + //Filtering out the ID field cuz Dillon doesn't like it. May want to filter out other fields in the future + var result bson.M err := collection.FindOne(ctx, filter).Decode(&result) - defer cancel() + defer cancel() - if err != nil { + if err != nil { if err == mongo.ErrNoDocuments { return false, err } @@ -216,18 +216,18 @@ func hasAdmin(w http.ResponseWriter, r *http.Request) { func GetUser(username string) (models.User, error) { - var user models.User + var user models.User - collection := mongoconn.Client.Database("netmaker").Collection("users") + collection := mongoconn.Client.Database("netmaker").Collection("users") - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - filter := bson.M{"username": username} - err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&user) + filter := bson.M{"username": username} + err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&user) - defer cancel() + defer cancel() - return user, err + return user, err } //Get an individual node. Nothin fancy here folks. @@ -235,7 +235,7 @@ func getUser(w http.ResponseWriter, r *http.Request) { // set header. w.Header().Set("Content-Type", "application/json") - var params = mux.Vars(r) + var params = mux.Vars(r) user, err := GetUser(params["username"]) @@ -249,51 +249,51 @@ func getUser(w http.ResponseWriter, r *http.Request) { func CreateUser(user models.User) (models.User, error) { - //encrypt that password so we never see it again - hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 5) + //encrypt that password so we never see it again + hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 5) - if err != nil { - return user, err - } - //set password to encrypted password - user.Password = string(hash) + if err != nil { + return user, err + } + //set password to encrypted password + user.Password = string(hash) - tokenString, _ := functions.CreateUserJWT(user.UserName, user.IsAdmin) + tokenString, _ := functions.CreateUserJWT(user.UserName, user.IsAdmin) - if tokenString == "" { - //returnErrorResponse(w, r, errorResponse) - return user, err - } + if tokenString == "" { + //returnErrorResponse(w, r, errorResponse) + return user, err + } - // connect db - collection := mongoconn.Client.Database("netmaker").Collection("users") - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + // connect db + collection := mongoconn.Client.Database("netmaker").Collection("users") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - // insert our node to the node db. - result, err := collection.InsertOne(ctx, user) - _ = result + // insert our node to the node db. + result, err := collection.InsertOne(ctx, user) + _ = result - defer cancel() + defer cancel() - return user, err + return user, err } func createAdmin(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") var errorResponse = models.ErrorResponse{ - Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", + Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", } hasadmin, err := HasAdmin() - if hasadmin { - errorResponse = models.ErrorResponse{ - Code: http.StatusUnauthorized, Message: "W1R3: Admin already exists! ", - } - returnErrorResponse(w, r, errorResponse) - return - } + if hasadmin { + errorResponse = models.ErrorResponse{ + Code: http.StatusUnauthorized, Message: "W1R3: Admin already exists! ", + } + returnErrorResponse(w, r, errorResponse) + return + } var admin models.User @@ -302,72 +302,71 @@ func createAdmin(w http.ResponseWriter, r *http.Request) { admin.IsAdmin = true - err = ValidateUser("create", admin) - if err != nil { + err = ValidateUser("create", admin) + if err != nil { json.NewEncoder(w).Encode(err) return - } + } - admin, err = CreateUser(admin) - if err != nil { + admin, err = CreateUser(admin) + if err != nil { json.NewEncoder(w).Encode(err) - return - } + return + } json.NewEncoder(w).Encode(admin) } func UpdateUser(userchange models.User, user models.User) (models.User, error) { - queryUser := user.UserName + queryUser := user.UserName - if userchange.UserName != "" { - user.UserName = userchange.UserName - } - if userchange.Password != "" { - //encrypt that password so we never see it again - hash, err := bcrypt.GenerateFromPassword([]byte(userchange.Password), 5) + if userchange.UserName != "" { + user.UserName = userchange.UserName + } + if userchange.Password != "" { + //encrypt that password so we never see it again + hash, err := bcrypt.GenerateFromPassword([]byte(userchange.Password), 5) - if err != nil { - return userchange, err - } - //set password to encrypted password - userchange.Password = string(hash) + if err != nil { + return userchange, err + } + //set password to encrypted password + userchange.Password = string(hash) - user.Password = userchange.Password - } - //collection := mongoconn.ConnectDB() - collection := mongoconn.Client.Database("netmaker").Collection("users") + user.Password = userchange.Password + } + //collection := mongoconn.ConnectDB() + collection := mongoconn.Client.Database("netmaker").Collection("users") - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - // Create filter - filter := bson.M{"username": queryUser} + // Create filter + filter := bson.M{"username": queryUser} - fmt.Println("Updating User " + user.UserName) + fmt.Println("Updating User " + user.UserName) + // prepare update model. + update := bson.D{ + {"$set", bson.D{ + {"username", user.UserName}, + {"password", user.Password}, + {"isadmin", user.IsAdmin}, + }}, + } + var userupdate models.User - // prepare update model. - update := bson.D{ - {"$set", bson.D{ - {"username", user.UserName}, - {"password", user.Password}, - {"isadmin", user.IsAdmin}, - }}, - } - var userupdate models.User - - errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&userupdate) + errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&userupdate) if errN != nil { - fmt.Println("Could not update: ") - fmt.Println(errN) - } else { + fmt.Println("Could not update: ") + fmt.Println(errN) + } else { fmt.Println("User updated successfully.") } - defer cancel() + defer cancel() - return userupdate, errN + return userupdate, errN } func updateUser(w http.ResponseWriter, r *http.Request) { @@ -379,61 +378,60 @@ func updateUser(w http.ResponseWriter, r *http.Request) { //start here user, err := GetUser(params["username"]) - if err != nil { - json.NewEncoder(w).Encode(err) - return - } - - - var userchange models.User - - // we decode our body request params - err = json.NewDecoder(r.Body).Decode(&userchange) if err != nil { - json.NewEncoder(w).Encode(err) - return - } + json.NewEncoder(w).Encode(err) + return + } + + var userchange models.User + + // we decode our body request params + err = json.NewDecoder(r.Body).Decode(&userchange) + if err != nil { + json.NewEncoder(w).Encode(err) + return + } userchange.IsAdmin = true - err = ValidateUser("update", userchange) + err = ValidateUser("update", userchange) - if err != nil { - json.NewEncoder(w).Encode(err) - return - } + if err != nil { + json.NewEncoder(w).Encode(err) + return + } user, err = UpdateUser(userchange, user) if err != nil { - json.NewEncoder(w).Encode(err) + json.NewEncoder(w).Encode(err) return } json.NewEncoder(w).Encode(user) } -func DeleteUser(user string) (bool, error) { +func DeleteUser(user string) (bool, error) { - deleted := false + deleted := false - collection := mongoconn.Client.Database("netmaker").Collection("users") + collection := mongoconn.Client.Database("netmaker").Collection("users") - filter := bson.M{"username": user} + filter := bson.M{"username": user} - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - result, err := collection.DeleteOne(ctx, filter) + result, err := collection.DeleteOne(ctx, filter) - deletecount := result.DeletedCount + deletecount := result.DeletedCount - if deletecount > 0 { - deleted = true - } + if deletecount > 0 { + deleted = true + } - defer cancel() + defer cancel() - return deleted, err + return deleted, err } func deleteUser(w http.ResponseWriter, r *http.Request) { @@ -446,45 +444,42 @@ func deleteUser(w http.ResponseWriter, r *http.Request) { success, err := DeleteUser(params["username"]) if err != nil { - returnErrorResponse(w, r, formatError(err, "internal")) - json.NewEncoder(w).Encode("Could not delete user " + params["username"]) + returnErrorResponse(w, r, formatError(err, "internal")) return } else if !success { - returnErrorResponse(w, r, formatError(errors.New("Delete unsuccessful."), "internal")) - json.NewEncoder(w).Encode("Could not delete user " + params["username"]) - return - } - + returnErrorResponse(w, r, formatError(errors.New("Delete unsuccessful."), "badrequest")) + return + } json.NewEncoder(w).Encode(params["username"] + " deleted.") } func ValidateUser(operation string, user models.User) error { - v := validator.New() + v := validator.New() - _ = v.RegisterValidation("username_unique", func(fl validator.FieldLevel) bool { + _ = v.RegisterValidation("username_unique", func(fl validator.FieldLevel) bool { _, err := GetUser(user.UserName) return err == nil || operation == "update" - }) + }) - _ = v.RegisterValidation("username_valid", func(fl validator.FieldLevel) bool { - isvalid := functions.NameInNodeCharSet(user.UserName) - return isvalid - }) + _ = v.RegisterValidation("username_valid", func(fl validator.FieldLevel) bool { + isvalid := functions.NameInNodeCharSet(user.UserName) + return isvalid + }) - _ = v.RegisterValidation("password_check", func(fl validator.FieldLevel) bool { - notEmptyCheck := user.Password != "" - goodLength := len(user.Password) > 5 - return (notEmptyCheck && goodLength) || operation == "update" - }) + _ = v.RegisterValidation("password_check", func(fl validator.FieldLevel) bool { + notEmptyCheck := user.Password != "" + goodLength := len(user.Password) > 5 + return (notEmptyCheck && goodLength) || operation == "update" + }) - err := v.Struct(user) + err := v.Struct(user) - if err != nil { - for _, e := range err.(validator.ValidationErrors) { - fmt.Println(e) - } - } - return err + if err != nil { + for _, e := range err.(validator.ValidationErrors) { + fmt.Println(e) + } + } + return err } diff --git a/test/user_test.go b/test/user_test.go index 7cc836ee..35eed608 100644 --- a/test/user_test.go +++ b/test/user_test.go @@ -11,7 +11,7 @@ import ( ) func TestAdminCreation(t *testing.T) { - t.Skip() + var admin models.UserAuthParams var user models.User admin.UserName = "admin" @@ -53,7 +53,7 @@ func TestAdminCreation(t *testing.T) { } func TestGetUser(t *testing.T) { - t.Skip() + if !adminExists(t) { t.Log("no admin - creating") addAdmin(t) @@ -62,7 +62,7 @@ func TestGetUser(t *testing.T) { } t.Run("GetUserWithValidToken", func(t *testing.T) { - t.Skip() + token, err := authenticate(t) assert.Nil(t, err, err) response, err := api(t, "", http.MethodGet, "http://localhost:8081/api/users/admin", token) @@ -84,7 +84,7 @@ func TestGetUser(t *testing.T) { } func TestUpdateUser(t *testing.T) { - t.Skip() + if !adminExists(t) { addAdmin(t) } @@ -120,23 +120,17 @@ func TestUpdateUser(t *testing.T) { } func TestDeleteUser(t *testing.T) { - t.Skip() + if !adminExists(t) { + t.Log("Creating Admin") addAdmin(t) } token, err := authenticate(t) assert.Nil(t, err, err) - t.Run("DeleteUser-WongAdmin", func(t *testing.T) { - //skip for now ... shouldn't panic - t.Skip() - function := func() { - _, _ = api(t, "", http.MethodDelete, "http://localhost:8081/api/users/xxxx", token) - } - assert.Panics(t, function, "") - }) t.Run("DeleteUser-InvalidCredentials", func(t *testing.T) { - response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/users/admin", "secretkey") + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/users/admin", "badcredentials") assert.Nil(t, err, err) + assert.Equal(t, http.StatusUnauthorized, response.StatusCode) var message models.ErrorResponse json.NewDecoder(response.Body).Decode(&message) assert.Equal(t, "W1R3: Error Verifying Auth Token.", message.Message) @@ -150,18 +144,21 @@ func TestDeleteUser(t *testing.T) { assert.Equal(t, "admin deleted.", body) assert.Equal(t, http.StatusOK, response.StatusCode) }) - t.Run("DeleteUser-NoAdmin", func(t *testing.T) { - //skip for now ... shouldn't panic - t.Skip() - function := func() { - _, _ = api(t, "", http.MethodDelete, "http://localhost:8081/api/users/admin", token) - } - assert.Panics(t, function, "") + t.Run("DeleteUser-NonExistantAdmin", func(t *testing.T) { + response, err := api(t, "", http.MethodDelete, "http://localhost:8081/api/users/admin", token) + assert.Nil(t, err, err) + assert.Equal(t, http.StatusBadRequest, response.StatusCode) + var message models.ErrorResponse + defer response.Body.Close() + json.NewDecoder(response.Body).Decode(&message) + assert.Equal(t, http.StatusBadRequest, message.Code) + assert.Equal(t, "Delete unsuccessful.", message.Message) }) + } func TestAuthenticateUser(t *testing.T) { - t.Skip() + cases := []AuthorizeTestCase{ AuthorizeTestCase{ testname: "Invalid User",