Browse Source

userdelete fixed

Matthew R Kasun 4 years ago
parent
commit
c62dc50d46
2 changed files with 279 additions and 287 deletions
  1. 260 265
      controllers/userHttpController.go
  2. 19 22
      test/user_test.go

+ 260 - 265
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)
+	//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
-            }
-
-	   //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)
-            }
+	} 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"
-
-                if len(tokenSplit) > 1 {
-                        authToken = tokenSplit[1]
-                } else {
-                        errorResponse = models.ErrorResponse{
-                                Code: http.StatusUnauthorized, Message: "W1R3: Missing Auth Token.",
-                        }
-                        returnErrorResponse(w, r, errorResponse)
+		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)
 			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
-
-    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)
+	queryUser := user.UserName
 
-        if err != nil {
-                return userchange, err
-        }
-        //set password to encrypted password
-        userchange.Password = string(hash)
+	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)
 
-        user.Password = userchange.Password
-    }
-        //collection := mongoconn.ConnectDB()
-        collection := mongoconn.Client.Database("netmaker").Collection("users")
+		if err != nil {
+			return userchange, err
+		}
+		//set password to encrypted password
+		userchange.Password = string(hash)
 
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+		user.Password = userchange.Password
+	}
+	//collection := mongoconn.ConnectDB()
+	collection := mongoconn.Client.Database("netmaker").Collection("users")
 
-        // Create filter
-        filter := bson.M{"username": queryUser}
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 
-        fmt.Println("Updating User " + user.UserName)
+	// Create filter
+	filter := bson.M{"username": queryUser}
 
+	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
-        }
-
+	if err != nil {
+		json.NewEncoder(w).Encode(err)
+		return
+	}
 
-        var userchange models.User
+	var userchange models.User
 
-        // we decode our body request params
-        err = json.NewDecoder(r.Body).Decode(&userchange)
+	// 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
+	}
 
 	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("password_check", func(fl validator.FieldLevel) bool {
-                notEmptyCheck := user.Password != ""
-                goodLength := len(user.Password) > 5
-                return (notEmptyCheck && goodLength) || operation == "update"
-        })
-
-        err := v.Struct(user)
-
-        if err != nil {
-                for _, e := range err.(validator.ValidationErrors) {
-                        fmt.Println(e)
-                }
-        }
-        return err
+	})
+
+	_ = 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"
+	})
+
+	err := v.Struct(user)
+
+	if err != nil {
+		for _, e := range err.(validator.ValidationErrors) {
+			fmt.Println(e)
+		}
+	}
+	return err
 }

+ 19 - 22
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",