diff --git a/configs/users.json b/configs/users.json index ce9334c8f14b0ffd190872804ee9f1211e6f5cde..7dcd174faac80582ebe9c249e0f1e18e5cde944e 100644 --- a/configs/users.json +++ b/configs/users.json @@ -24,7 +24,7 @@ "id": 4, "idOAuth": "", "login": "admin", - "role": "ADMINS", + "role": "ADMIN", "passwordHash": "$2a$10$PgiAoLxZhgNtr7kRK/DH5ezwT./7vRkWqFNEtJD1670z3Zf60HqgG" }, { @@ -32,7 +32,7 @@ "idOAuth": "1", "login": "ADMIN", "displayName": "Ad MIN", - "role": "ADMINS" + "role": "ADMIN" }, { "id": 6, diff --git a/internal/models/bankAccounts.go b/internal/models/bankAccounts.go index ef1e890104152456b40efc887d32d98e43bdcba3..bc0755175397612b9c4bb23a6f06c3183536d6f0 100644 --- a/internal/models/bankAccounts.go +++ b/internal/models/bankAccounts.go @@ -15,6 +15,18 @@ func (d *DataHandler) HandleBankAccounts(w http.ResponseWriter, r *http.Request) case "GET": switch auth.GetLoggedUserTechnical(w, r).Role { case "ADMIN": + if id != 0 { + var o BankAccount + if err := d.db.Preload("Operations").First(&o, id).Error; err != nil { + http.Error(w, "id does not exist", http.StatusNotFound) + return + } + json.NewEncoder(w).Encode(o) + } else { + var o []BankAccount + d.db.Preload("Operations").Find(&o) + json.NewEncoder(w).Encode(o) + } case "BANKER": user := d.getLoggedUser(w, r).(UserBanker) if id != 0 { @@ -55,6 +67,16 @@ func (d *DataHandler) HandleBankAccounts(w http.ResponseWriter, r *http.Request) case "POST": switch auth.GetLoggedUserTechnical(w, r).Role { case "ADMIN": + var o BankAccount + err := json.NewDecoder(r.Body).Decode(&o) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + if o.UserClientID != 0 { + d.db.Create(&o) + } else { + http.Error(w, "id of UserClient is missing", http.StatusNotFound) + } case "BANKER": user := d.getLoggedUser(w, r).(UserBanker) var o BankAccount @@ -82,6 +104,16 @@ func (d *DataHandler) HandleBankAccounts(w http.ResponseWriter, r *http.Request) case "DELETE": switch auth.GetLoggedUserTechnical(w, r).Role { case "ADMIN": + if id != 0 { + var o BankAccount + if err := d.db.First(&o, id).Error; err != nil { + http.Error(w, "id does not exist", http.StatusNotFound) + return + } + d.db.Delete(&o) + } else { + http.Error(w, "id is missing", http.StatusNotFound) + } case "BANKER": user := d.getLoggedUser(w, r).(UserBanker) if id != 0 { @@ -90,20 +122,17 @@ func (d *DataHandler) HandleBankAccounts(w http.ResponseWriter, r *http.Request) http.Error(w, "id does not exist", http.StatusNotFound) return } - if o.UserClientID != 0 { - var userClient UserClient - if err := d.db.Where("id = ? and user_banker_id = ?", o.UserClientID, user.ID).First(&userClient).Error; err != nil { - http.Error(w, "You can not access this ressource", http.StatusForbidden) - return - } - d.db.Delete(&o) - } else { - http.Error(w, "id of UserClient is missing", http.StatusNotFound) + var userClient UserClient + if err := d.db.Where("id = ? and user_banker_id = ?", o.UserClientID, user.ID).First(&userClient).Error; err != nil { + http.Error(w, "You can not access this ressource", http.StatusForbidden) + return } + d.db.Delete(&o) } else { http.Error(w, "id is missing", http.StatusNotFound) } case "CLIENT": + http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed) default: http.Error(w, "Could not get role of logged user", http.StatusInternalServerError) } diff --git a/internal/models/bankers.go b/internal/models/bankers.go index c7a218f774272f57c50f88a69c3854eb836c062b..d1b667a7ec8d86e1fadab4a80e7299b1b9d7d8cc 100644 --- a/internal/models/bankers.go +++ b/internal/models/bankers.go @@ -10,12 +10,11 @@ import ( ) func (d *DataHandler) HandleBankers(w http.ResponseWriter, r *http.Request) { - id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/UserClients/")) + id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/UserBankers/")) switch method := r.Method; method { case "GET": switch auth.GetLoggedUserTechnical(w, r).Role { case "ADMIN": - case "BANKER": if id != 0 { var o UserBanker if err := d.db.Preload("UserClients").Where("id = ?", id).First(&o).Error; err != nil { @@ -28,6 +27,22 @@ func (d *DataHandler) HandleBankers(w http.ResponseWriter, r *http.Request) { d.db.Preload("UserClients").Find(&o) json.NewEncoder(w).Encode(o) } + case "BANKER": + user := d.getLoggedUser(w, r).(UserBanker) + if id != 0 { + var o UserBanker + if err := d.db.Preload("UserClients").Where("id = ?", id).First(&o).Error; err != nil { + http.Error(w, "id does not exist", http.StatusNotFound) + return + } + if o.ID != user.ID { + http.Error(w, "You can not access this ressource", http.StatusForbidden) + return + } + json.NewEncoder(w).Encode(o) + } else { + http.Error(w, "You can not access this ressource", http.StatusForbidden) + } case "CLIENT": user := d.getLoggedUser(w, r).(UserClient) if id != 0 && int(user.ID) == id { @@ -51,31 +66,36 @@ func (d *DataHandler) HandleBankers(w http.ResponseWriter, r *http.Request) { case "POST": switch auth.GetLoggedUserTechnical(w, r).Role { case "ADMIN": - case "BANKER": - case "CLIENT": + var o UserBanker + err := json.NewDecoder(r.Body).Decode(&o) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + d.db.Create(&o) + case "BANKER", "CLIENT": + http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed) default: http.Error(w, "Could not get role of logged user", http.StatusInternalServerError) } - // var o UserBanker - // err := json.NewDecoder(r.Body).Decode(&o) - // if err != nil { - // http.Error(w, err.Error(), http.StatusInternalServerError) - // } - // d.db.Create(&o) + case "DELETE": switch auth.GetLoggedUserTechnical(w, r).Role { case "ADMIN": - case "BANKER": - case "CLIENT": + if id != 0 { + var o UserBanker + if err := d.db.First(&o, id).Error; err != nil { + http.Error(w, "id does not exist", http.StatusNotFound) + return + } + d.db.Delete(&o) + } else { + http.Error(w, "id is missing", http.StatusNotFound) + } + case "BANKER", "CLIENT": + http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed) default: http.Error(w, "Could not get role of logged user", http.StatusInternalServerError) } - // if id != 0 { - // var o UserClient - // d.db.Delete(&o) - // } else { - // http.Error(w, "id is missing", http.StatusNotFound) - // } default: http.Error(w, "method not allowed", 400) diff --git a/internal/models/clients.go b/internal/models/clients.go index 4eb0b91e22067570ca14fc8eb48076d1cd247060..a58b1ad1fdedf66fb6c7dba5276dddebc9fbef96 100644 --- a/internal/models/clients.go +++ b/internal/models/clients.go @@ -17,6 +17,18 @@ func (d *DataHandler) HandleClients(w http.ResponseWriter, r *http.Request) { switch auth.GetLoggedUserTechnical(w, r).Role { case "ADMIN": + if id != 0 { + var o UserClient + if err := d.db.Preload("BankAccounts").Where("id = ?", id).First(&o).Error; err != nil { + http.Error(w, "id does not exist", http.StatusNotFound) + return + } + json.NewEncoder(w).Encode(o) + } else { + var o []UserClient + d.db.Preload("BankAccounts").Find(&o) + json.NewEncoder(w).Encode(o) + } case "BANKER": user := d.getLoggedUser(w, r).(UserBanker) if id != 0 { @@ -58,6 +70,12 @@ func (d *DataHandler) HandleClients(w http.ResponseWriter, r *http.Request) { case "POST": switch auth.GetLoggedUserTechnical(w, r).Role { case "ADMIN": + var o UserClient + err := json.NewDecoder(r.Body).Decode(&o) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + d.db.Create(&o) case "BANKER": user := d.getLoggedUser(w, r).(UserBanker) var o UserClient @@ -75,6 +93,19 @@ func (d *DataHandler) HandleClients(w http.ResponseWriter, r *http.Request) { case "DELETE": switch auth.GetLoggedUserTechnical(w, r).Role { case "ADMIN": + if id != 0 { + var o UserClient + if err := d.db.Where("id = ?", id).First(&o).Error; err != nil { + http.Error(w, "id does not exist", http.StatusNotFound) + return + } + // Delete bank accounts of user + d.db.Where("user_client_id = ?", o.ID).Delete(&BankAccount{}) + + d.db.Delete(&o) + } else { + http.Error(w, "id is missing", http.StatusNotFound) + } case "BANKER": user := d.getLoggedUser(w, r).(UserBanker) if id != 0 { @@ -84,7 +115,7 @@ func (d *DataHandler) HandleClients(w http.ResponseWriter, r *http.Request) { return } if o.UserBankerID != user.ID { - http.Error(w, "You can not access this ressource", http.StatusForbidden) + http.Error(w, "You're not authorize to execute this method on this ressource.", http.StatusMethodNotAllowed) return } // Delete bank accounts of user diff --git a/internal/models/models.go b/internal/models/models.go index f56d650a31e891108a94c30315fdc21701c56a55..e6c6f3162a75d2ce282a3beb3cd7f551a7ccb5de 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -45,7 +45,7 @@ func (d *DataHandler) ProcessAPI(w http.ResponseWriter, r *http.Request) { switch api { case "UserClients": d.HandleClients(w, r) - case "UserBanker": + case "UserBankers": d.HandleBankers(w, r) case "BankAccounts": d.HandleBankAccounts(w, r) diff --git a/internal/models/operations.go b/internal/models/operations.go index 766e42651b626cdb39b396b7262645acf9c79950..5a2cb053b3cd50ad41f977e3bddce04924936576 100644 --- a/internal/models/operations.go +++ b/internal/models/operations.go @@ -15,8 +15,7 @@ func (d *DataHandler) HandleOperations(w http.ResponseWriter, r *http.Request) { switch method := r.Method; method { case "GET": switch auth.GetLoggedUserTechnical(w, r).Role { - case "ADMIN": - case "BANKER": + case "ADMIN", "BANKER", "CLIENT": if id != 0 { var o Operation if err := d.db.First(&o, id).Error; err != nil { @@ -29,14 +28,12 @@ func (d *DataHandler) HandleOperations(w http.ResponseWriter, r *http.Request) { d.db.Find(&o) json.NewEncoder(w).Encode(o) } - case "CLIENT": default: http.Error(w, "Could not get role of logged user", http.StatusInternalServerError) } case "POST": switch auth.GetLoggedUserTechnical(w, r).Role { - case "ADMIN": - case "BANKER": + case "ADMIN", "BANKER", "CLIENT": var o Operation err := json.NewDecoder(r.Body).Decode(&o) if err != nil { @@ -45,41 +42,44 @@ func (d *DataHandler) HandleOperations(w http.ResponseWriter, r *http.Request) { var debtor BankAccount var creditor BankAccount - if err := d.db.First(&debtor, o.Debtor).Error; err == nil { - if (debtor.Amount + o.Amount) >= debtor.BankOverdraft { - if err := d.db.First(&creditor, o.Creditor).Error; err == nil { - // Update BankAccounts - debtor.Amount += o.Amount - creditor.Amount -= o.Amount - d.db.Save(&debtor) - d.db.Save(&creditor) + if err := d.db.Where("id = ?", o.Debtor).First(&debtor).Error; err != nil { + http.Error(w, "Can not find debtor account", http.StatusInternalServerError) + return + } + if err := d.db.First(&creditor, o.Creditor).Error; err != nil { + http.Error(w, "Can not find creditor account", http.StatusInternalServerError) + return + } + if (debtor.Amount + o.Amount) <= debtor.BankOverdraft { + http.Error(w, "Not enough money", http.StatusExpectationFailed) + return + } + // Update BankAccounts + debtor.Amount += o.Amount + creditor.Amount -= o.Amount + d.db.Save(&debtor) + d.db.Save(&creditor) - now := time.Now() - o.Date = now - d.db.Create(&o) + now := time.Now() + o.Date = now + d.db.Create(&o) - // Add the operation to creditor - op := Operation{ - Debtor: o.Creditor, - Amount: -o.Amount, - Date: now, - Creditor: o.Debtor, - } - d.db.Create(&op) - } - } else { - http.Error(w, "Not enough money", http.StatusExpectationFailed) - } + // Add the operation to creditor + op := Operation{ + Debtor: o.Creditor, + Amount: -o.Amount, + Date: now, + Creditor: o.Debtor, } - case "CLIENT": + d.db.Create(&op) + default: http.Error(w, "Could not get role of logged user", http.StatusInternalServerError) } case "DELETE": switch auth.GetLoggedUserTechnical(w, r).Role { - case "ADMIN": - case "BANKER": + case "ADMIN", "BANKER": if id != 0 { var o Operation if err := d.db.First(&o, id).Error; err != nil { diff --git a/internal/rootmux/admin_test.go b/internal/rootmux/admin_test.go new file mode 100644 index 0000000000000000000000000000000000000000..efea4aaee99c29983d87b631605503ebee3ad5da --- /dev/null +++ b/internal/rootmux/admin_test.go @@ -0,0 +1,82 @@ +package rootmux + +import ( + "encoding/json" + "testing" + + "forge.grandlyon.com/apoyen/sdk-go/pkg/auth" + "forge.grandlyon.com/apoyen/sdk-go/pkg/tester" +) + +/** +ADMIN TESTS (those tests are to check the admins authorization) +**/ +func AdminTests(t *testing.T) { + // Create the tester + ts, do, _ := createTester(t) + defer ts.Close() // Close the tester + tests := func() { + // Get the XSRF Token + response := do("GET", "/api/common/WhoAmI", noH, "", 200, "") + token := auth.TokenData{} + json.Unmarshal([]byte(response), &token) + xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} + + // Create a banker + do("POST", "/api/UserBankers", xsrfHeader, `{"UserID":8,"Name":"Banker 2"}`, 200, ``) + // Get a banker + do("GET", "/api/UserBankers/1", xsrfHeader, "", 200, `{"ID":1,"UserID":3,"Name":"Banker","UserClients":[{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":null}]}`) + // Try to gel all bankers + do("GET", "/api/UserBankers/", xsrfHeader, "", 200, `[{"ID":1,"UserID":3,"Name":"Banker","UserClients":[{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":null}]},{"ID":2,"UserID":6,"Name":"Banker 2","UserClients":[{"ID":2,"UserID":2,"Name":"Boulangerie","UserBankerID":2,"BankAccounts":null}]},{"ID":3,"UserID":8,"Name":"Banker 2","UserClients":[]}]`) + // Try to delete a banker + do("DELETE", "/api/UserBankers/3", xsrfHeader, ``, 200, ``) + + // Try to create a client + do("POST", "/api/UserClients", xsrfHeader, `{"UserID":7,"Name":"Dupond","UserBankerID":1}`, 200, "") + // Try to get one of the banker's client + do("GET", "/api/UserClients/1", xsrfHeader, "", 200, `{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":null}]}`) + // Try to get all the clients of the banker + do("GET", "/api/UserClients", xsrfHeader, "", 200, `[{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":null}]},{"ID":2,"UserID":2,"Name":"Boulangerie","UserBankerID":2,"BankAccounts":[{"ID":2,"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4745,"BankOverdraft":-500,"Operations":null}]},{"ID":3,"UserID":7,"Name":"Dupond","UserBankerID":1,"BankAccounts":[]}]`) + // Try to delete a client + do("DELETE", "/api/UserClients/3", xsrfHeader, ``, 200, ``) + + // Add an other bank account to client + do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0}`, 200, ``) + // Get account where id=1 + do("GET", "/api/BankAccounts/1", xsrfHeader, "", 200, `{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":[]}`) + // Get all Bank accounts + do("GET", "/api/BankAccounts/", xsrfHeader, "", 200, `[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":[]},{"ID":2,"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4745,"BankOverdraft":-500,"Operations":[]},{"ID":3,"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0,"Operations":[]}]`) + // Try to delete the saving account of Dupond + do("DELETE", "/api/BankAccounts/3", xsrfHeader, ``, 200, "") + + // Add operation between client and Bakery + do("POST", "/api/Operations", xsrfHeader, `{"Debtor":1,"Amount":-100,"Creditor":2}`, 200, "") + // Get operation where id=1 + do("GET", "/api/Operations/1", xsrfHeader, "", 200, `{"ID":1,"Debtor":1,"Amount":-100`) + // Try to delete the first operation + do("DELETE", "/api/Operations/1", xsrfHeader, ``, 200, "") + } + userTests := func() { + response := do("GET", "/api/common/WhoAmI", noH, "", 200, "") + token := auth.TokenData{} + json.Unmarshal([]byte(response), &token) + xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} + + // Create a Client + do("POST", "/api/admin/users/", xsrfHeader, `{"login":"UserTest","password": "password","role":"CLIENT"}`, 200, `[{"id":1,"idOAuth":"","login":"Dupond"`) + // Create a Banker + do("POST", "/api/admin/users/", xsrfHeader, `{"login":"BankerTest","password": "password","role":"BANKER"}`, 200, `[{"id":1,"idOAuth":"","login":"Dupond"`) + // Get all users + do("GET", "/api/admin/users/", xsrfHeader, ``, 200, `[{"id":1,"idOAuth":"","login":"Dupond"`) + // Delete created users + do("DELETE", "/api/admin/users/7", xsrfHeader, ``, 200, ``) + do("DELETE", "/api/admin/users/8", xsrfHeader, ``, 200, ``) + } + // Do an OAuth2 login with an known admin + do("GET", "/OAuth2Login", noH, "", 200, "<!DOCTYPE html>") + tests() + userTests() + // Try to logout (must pass) + do("GET", "/Logout", noH, "", 200, "Logout OK") + +} diff --git a/internal/rootmux/banker_test.go b/internal/rootmux/banker_test.go new file mode 100644 index 0000000000000000000000000000000000000000..3e78e49f8bbb4e6a8b8d119ab4fe05c4fcb32e5a --- /dev/null +++ b/internal/rootmux/banker_test.go @@ -0,0 +1,76 @@ +package rootmux + +import ( + "encoding/json" + "testing" + + "forge.grandlyon.com/apoyen/sdk-go/pkg/auth" + "forge.grandlyon.com/apoyen/sdk-go/pkg/tester" +) + +/** +Banker TESTS (those tests are to check the bankers rights) +**/ +func BankerTests(t *testing.T) { + // Create the tester + ts, do, _ := createTester(t) + defer ts.Close() // Close the tester + tests := func() { + // Get the XSRF Token + response := do("GET", "/api/common/WhoAmI", noH, "", 200, "") + token := auth.TokenData{} + json.Unmarshal([]byte(response), &token) + xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} + + // Create a banker should fail with 405 + do("POST", "/api/UserBankers", xsrfHeader, `{"UserID":8,"Name":"Banker 2"}`, 405, `You're not authorize to execute this method on this ressource.`) + // Get the banker connected + do("GET", "/api/UserBankers/1", xsrfHeader, "", 200, `{"ID":1,"UserID":3,"Name":"Banker","UserClients":[{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":null}]}`) + // Try to get an other banker + do("GET", "/api/UserBankers/2", xsrfHeader, "", 403, `You can not access this ressource`) + // Try to gel all bankers + do("GET", "/api/UserBankers/", xsrfHeader, "", 403, `You can not access this ressource`) + // Try to delete an other banker should fail with 405 + do("DELETE", "/api/UserBankers/2", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`) + + // Try to create a client + do("POST", "/api/UserClients", xsrfHeader, `{"UserID":7,"Name":"Dupond","UserBankerID":1}`, 200, "") + // Try to get one of the banker's client + do("GET", "/api/UserClients/1", xsrfHeader, "", 200, `{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":null}]}`) + // Try to get another banker's client should fail with 405 + do("GET", "/api/UserClients/2", xsrfHeader, "", 403, `You can not access this ressource`) + // Try to get all the clients of the banker + do("GET", "/api/UserClients", xsrfHeader, "", 200, `[{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":null}]},{"ID":2,"UserID":2,"Name":"Boulangerie","UserBankerID":2,"BankAccounts":[{"ID":2,"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4745,"BankOverdraft":-500,"Operations":null}]},{"ID":3,"UserID":7,"Name":"Dupond","UserBankerID":1,"BankAccounts":[]}]`) + // Try to delete a banker client + do("DELETE", "/api/UserClients/3", xsrfHeader, ``, 200, ``) + // Try to delete the bakery client should fail with 405 + do("DELETE", "/api/UserClients/2", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`) + + // Add an other bank account to client + do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0}`, 200, ``) + // Add a bank account to another banker's client should fail with 405 + do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"02-02","UserClientID":2,"Type":"saving-account","Amount":3978,"BankOverdraft":0}`, 403, `You can not access this ressource`) + // Get account where id=1 + do("GET", "/api/BankAccounts/1", xsrfHeader, "", 200, `{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":[]}`) + // Get account where id=2 should fail as it is another banker's client's account + do("GET", "/api/BankAccounts/2", xsrfHeader, "", 403, `You can not access this ressource`) + // Get all Bank account should return only the bank accounts of the bankers'client + do("GET", "/api/BankAccounts/", xsrfHeader, "", 200, `[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":[]},{"ID":3,"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0,"Operations":[]}]`) + // Try to delete the saving account of Dupond + do("DELETE", "/api/BankAccounts/3", xsrfHeader, ``, 200, "") + // Try to delete the saving account of Bakery should fail with 405 + do("DELETE", "/api/BankAccounts/2", xsrfHeader, ``, 403, "You can not access this ressource") + + // Add operation between client and Bakery + do("POST", "/api/Operations", xsrfHeader, `{"Debtor":1,"Amount":-100,"Creditor":2}`, 200, "") + // Get operation where id=1 + do("GET", "/api/Operations/1", xsrfHeader, "", 200, `{"ID":1,"Debtor":1,"Amount":-100`) + // Try to delete the first operation + do("DELETE", "/api/Operations/1", xsrfHeader, ``, 200, "") + } + // Do a in memory login with an known admin + do("POST", "/Login", noH, `{"login": "banker","password": "password"}`, 200, "") + tests() + // Try to logout (must pass) + do("GET", "/Logout", noH, "", 200, "Logout OK") +} diff --git a/internal/rootmux/client_test.go b/internal/rootmux/client_test.go new file mode 100644 index 0000000000000000000000000000000000000000..0b04943c8397abb6c94575e575f7431252c02f91 --- /dev/null +++ b/internal/rootmux/client_test.go @@ -0,0 +1,63 @@ +package rootmux + +import ( + "encoding/json" + "testing" + + "forge.grandlyon.com/apoyen/sdk-go/pkg/auth" + "forge.grandlyon.com/apoyen/sdk-go/pkg/tester" +) + +/** +CLIENT TESTS (this tests are to check that a normally logged user can access the apps that is allowed to and only that) +**/ +func ClientTests(t *testing.T) { + // Create the tester + ts, do, _ := createTester(t) + defer ts.Close() // Close the tester + tests := func() { + // Get the XSRF Token + response := do("GET", "/api/common/WhoAmI", noH, "", 200, "") + token := auth.TokenData{} + json.Unmarshal([]byte(response), &token) + xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} + + // Try to create a client should fail with 405 + do("POST", "/api/UserClients", xsrfHeader, `{"ID":11,"UserID":"11","Name":"Dupont"}`, 405, "You're not authorize to execute this method on this ressource.") + // Try to create a banker should fail with 405 + do("POST", "/api/UserBankers", xsrfHeader, `{"ID":11,"UserID":"11","Name":"Banker"}`, 405, "You're not authorize to execute this method on this ressource.") + // Try to create a BankAccount should fail with 405 + do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0}`, 405, "You're not authorize to execute this method on this ressource.") + // Client should be able to create an operation + do("POST", "/api/Operations", xsrfHeader, `{"Debtor":1,"Amount":-100,"Creditor":2}`, 200, ``) + + // Get the previous operation between Dupond and Bakery + do("GET", "/api/Operations/1", xsrfHeader, "", 200, `{"ID":1,"Debtor":1,"Amount":-100`) + // Get all operations + do("GET", "/api/Operations/", xsrfHeader, "", 200, `[{"ID":1,"Debtor":1,"Amount":-100`) + // Get Dupond Bank account + do("GET", "/api/BankAccounts/1", xsrfHeader, "", 200, `{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":[{"ID":1,"Debtor":1,"Amount":-100`) + // Get all accounts of the user client and only those ones + do("GET", "/api/BankAccounts/", xsrfHeader, "", 200, `[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":[{"ID":1,"Debtor":1,"Amount":-100`) + // Get client Dupond by id + do("GET", "/api/UserClients/1", xsrfHeader, "", 200, `{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":null}]}`) + // Get client Bakery should fail with 403 + do("GET", "/api/UserClients/2", xsrfHeader, "", 403, `You can not access this ressource`) + // Try to get all the clients return only Dupond + do("GET", "/api/UserClients", xsrfHeader, "", 200, `[{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":null}]}]`) + + // Try to delete the first operation should fail + do("DELETE", "/api/Operations/1", xsrfHeader, ``, 405, "You're not authorize to execute this method on this ressource.") + // Try to delete the saving account of Dupond should fail + do("DELETE", "/api/BankAccounts/2", xsrfHeader, ``, 405, "You're not authorize to execute this method on this ressource.") + // Try to delete the client Dupond should fail + do("DELETE", "/api/UserClients/2", xsrfHeader, ``, 405, "You're not authorize to execute this method on this ressource.") + } + // Do a in memory login with an known user + do("POST", "/Login", noH, `{"login": "Dupond","password": "password"}`, 200, "") + // Run the tests + tests() + // Try to logout (must pass) + do("GET", "/Logout", noH, "", 200, "Logout OK") + +} diff --git a/internal/rootmux/rootmux.go b/internal/rootmux/rootmux.go index cc1eeeceebc8c604d7dc5969f4c2891fbe92f0a0..0f7915defb9969d52308202ae7df5f629a1e73e1 100644 --- a/internal/rootmux/rootmux.go +++ b/internal/rootmux/rootmux.go @@ -42,7 +42,7 @@ func CreateRootMux(port int, staticDir string) RootMux { // ADMIN API ENDPOINTS adminMux := http.NewServeMux() adminMux.HandleFunc("/users/", auth.ProcessUsers) - mainMux.Handle("/api/admin/", http.StripPrefix("/api/admin", auth.ValidateAuthMiddleware(adminMux, []string{os.Getenv("ADMIN_GROUP")}, true))) + mainMux.Handle("/api/admin/", http.StripPrefix("/api/admin", auth.ValidateAuthMiddleware(adminMux, []string{"ADMIN"}, true))) // Serve static files falling back to serving index.html mainMux.Handle("/", middlewares.NoCache(http.FileServer(&common.FallBackWrapper{Assets: http.Dir(staticDir)}))) // Put it together into the main handler diff --git a/internal/rootmux/rootmux_test.go b/internal/rootmux/rootmux_test.go index 1d06b0d1aaffd86cd02e20a7d53e754c228c9030..f5056929747e961c1f300fd8bf8a1f7a5fe624a2 100644 --- a/internal/rootmux/rootmux_test.go +++ b/internal/rootmux/rootmux_test.go @@ -31,9 +31,10 @@ func init() { } func TestAll(t *testing.T) { + os.Mkdir("data", os.ModePerm) + os.Create("./data/test.db") // Set the users file auth.UsersFile = "../../configs/users.json" - resetData() // Create the mock OAuth2 server oAuth2Server := httptest.NewServer(mocks.CreateMockOAuth2()) defer oAuth2Server.Close() @@ -53,10 +54,14 @@ func TestAll(t *testing.T) { os.Setenv("AUTH_URL", oAuth2Server.URL+"/auth") // Set the server to access the correct OAuth2Endpoint os.Setenv("USERINFO_URL", oAuth2Server.URL+"/admininfo") - AdminTests(t) - UnLoggedTests(t) - UserTests(t) + resetData(t) + UnLoggedUserTests(t) + resetData(t) + ClientTests(t) + resetData(t) BankerTests(t) + resetData(t) + AdminTests(t) os.RemoveAll("./data") } @@ -72,285 +77,51 @@ func Oauth2Tests(t *testing.T) { do("GET", "/OAuth2Login", noH, "", 500, "invalid oauth state") } -/** -ADMIN TESTS (those tests are to check the admins authorization) -**/ -func AdminTests(t *testing.T) { - // Create the tester - ts, do, _ := createTester(t) +// func createUserTests(t *testing.T) { - defer ts.Close() // Close the tester - do("GET", "/OAuth2Login", noH, "", 200, "<!DOCTYPE html>") - response := do("GET", "/api/common/WhoAmI", noH, "", 200, "") - token := auth.TokenData{} - json.Unmarshal([]byte(response), &token) - xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} +// } - do("POST", "/api/admin/users/", xsrfHeader, `{"login":"UserTest","password": "password","role":"USER"}`, 200, `[{"id":1,"idOAuth":"","login":"Dupond"`) - do("GET", "/api/admin/users/", xsrfHeader, ``, 200, `[{"id":1,"idOAuth":"","login":"Dupond"`) - do("DELETE", "/api/admin/users/7", xsrfHeader, ``, 200, ``) -} +// func appTests(t *testing.T) { +// // Add invalid operation between client and Bakery must be refused with 417 (Expectation failed) +// // do("POST", "/api/Operations", xsrfHeader, `{"Debtor":1,"Amount":-1789,"Creditor":3}`, 417, "Not enough money") -/** -UNLOGGED USER TESTS (this tests are to check that the security protections works) -**/ -func UnLoggedTests(t *testing.T) { - // Create the tester - ts, do, _ := createTester(t) +// } - defer ts.Close() // Close the tester - // Without authent API calls must fails with 403 user could not be got from context - // Try to get the first client should fail - do("GET", "/api/UserClients/1", noH, "", 401, `error extracting token`) - // Try to get all clients should fail - do("GET", "/api/UserClients", noH, "", 401, `error extracting token`) - // Try to get the first operation should fail - do("GET", "/api/Operations/1", noH, "", 401, `error extracting token`) - // Try to get all operations should fail - do("GET", "/api/Operations", noH, "", 401, `error extracting token`) - // Try to get the first BankAccount should fail - do("GET", "/api/BankAccounts/1", noH, "", 401, `error extracting token`) - // Try to get all BankAccounts should fail - do("GET", "/api/BankAccounts", noH, "", 401, `error extracting token`) - - // Unlogged user should not be able to create a Client - do("POST", "/api/UserClients", noH, `{"Name":"Dupond"}`, 401, `error extracting token`) - // Unlogged user should not be able to create a Bank Account - do("POST", "/api/BankAccounts", noH, `{"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100}`, 401, `error extracting token`) - // Unlogged user should not be able to create an Operation - do("POST", "/api/Operations", noH, `{"Debtor":1,"Amount":-100,"Creditor":3}`, 401, `error extracting token`) - - // Unlogged user should not be able to delete an Operation - do("DELETE", "/api/Operations/1", noH, ``, 401, "error extracting token") - // Unlogged user should not be able to delete a BankAccount - do("DELETE", "/api/BankAccounts/2", noH, ``, 401, "error extracting token") - // Unlogged user should not be able to delete a Client - do("DELETE", "/api/UserClients/2", noH, ``, 401, "error extracting token") - - // Try to access the main page (must pass) - do("GET", "/", noH, "", 200, "<!DOCTYPE html>") - // Try to get the user informations (must fail) - do("GET", "/api/common/WhoAmI", noH, "", 401, "error extracting token") - // Do a in memory login with an unknown user - do("POST", "/Login", noH, `{"login": "unknownuser","password": "password"}`, http.StatusForbidden, `user not found`) - // Do a in memory login with a known user but bad password - do("POST", "/Login", noH, `{"login": "admin","password": "badpassword"}`, http.StatusForbidden, `user not found`) -} +func resetData(t *testing.T) { + os.RemoveAll("./data") + os.Mkdir("data", os.ModePerm) + os.Create("./data/test.db") -/** -USER TESTS (this tests are to check that a normally logged user can access the apps that is allowed to and only that) -**/ -func UserTests(t *testing.T) { - // Create the tester ts, do, _ := createTester(t) defer ts.Close() // Close the tester - dataInit := func() { - // Do a in memory login with an known admin - do("POST", "/Login", noH, `{"login": "banker","password": "password"}`, 200, "") - // Get the XSRF Token - response := do("GET", "/api/common/WhoAmI", noH, "", 200, "") - token := auth.TokenData{} - json.Unmarshal([]byte(response), &token) - xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} - do("POST", "/api/UserClients", xsrfHeader, `{"ID":1,"UserID":1,"Name":"Dupond"}`, 200, "") - do("POST", "/api/UserClients", xsrfHeader, `{"ID":2,"UserID":2,"Name":"Boulangerie"}`, 200, "") - - do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100}`, 200, "") - do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0}`, 200, "") - do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4745,"BankOverdraft":-500}`, 200, "") - - do("GET", "/Logout", noH, "", 200, "Logout OK") - } - dataInit() - tests := func() { - // Get the XSRF Token + // Init Data in DB tests + init := func() { response := do("GET", "/api/common/WhoAmI", noH, "", 200, "") token := auth.TokenData{} json.Unmarshal([]byte(response), &token) xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} - - // Try to create a client should fail with 405 - do("POST", "/api/UserClients", xsrfHeader, `{"ID":11,"UserID":"11","Name":"Dupont"}`, 405, "You're not authorize to execute this method on this ressource.") - // Try to create a BankAccount should fail with 405 - do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100}`, 405, "You're not authorize to execute this method on this ressource.") - - // Client should be able to create an operation - do("POST", "/api/Operations", xsrfHeader, `{"Debtor":1,"Amount":-100,"Creditor":3}`, 200, "") - // Get operation between client and Bakery - do("GET", "/api/Operations/1", xsrfHeader, "", 200, `{"ID":1,"Debtor":1,"Amount":-100`) - // Get Operations for creditor (opposite operation should have been registered) - do("GET", "/api/Operations/2", xsrfHeader, "", 200, `{"ID":2,"Debtor":3,"Amount":100`) - - // Verify operation on client Dupond checking-account - do("GET", "/api/BankAccounts/1", xsrfHeader, "", 200, `{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":[{"ID":1,"Debtor":1,"Amount":-100`) - // Verify operation on client Bakery checking-account - do("GET", "/api/BankAccounts/3", xsrfHeader, "", 403, `You can not access this ressource`) - // Get all accounts of the user client and only those ones - do("GET", "/api/BankAccounts/", xsrfHeader, "", 200, `[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":[{"ID":1,"Debtor":1,"Amount":-100`) - - // Get client Dupond with his banks accounts and operations up to date (-100€ on checking-account) - do("GET", "/api/UserClients/2", xsrfHeader, "", 403, `You can not access this ressource`) - // Get client Bakery with his banks accounts and operations up to date (+100€ on checking-account) - do("GET", "/api/UserClients/1", xsrfHeader, "", 200, `{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":null},{"ID":2,"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0,"Operations":null}]}`) - // Try to get all the clients - do("GET", "/api/UserClients", xsrfHeader, "", 200, `[{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":null},{"ID":2,"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0,"Operations":null}]}]`) - - // Try to delete the first operation should fail - do("DELETE", "/api/Operations/1", xsrfHeader, ``, 405, "You're not authorize to execute this method on this ressource.") - // Try to delete the saving account of Dupond should fail - do("DELETE", "/api/BankAccounts/2", xsrfHeader, ``, 405, "You're not authorize to execute this method on this ressource.") - // Try to delete the client Dupond should fail - do("DELETE", "/api/UserClients/2", xsrfHeader, ``, 405, "You're not authorize to execute this method on this ressource.") - } - // Do a in memory login with an known user - do("POST", "/Login", noH, `{"login": "Dupond","password": "password"}`, 200, "") - // Run the tests - tests() - // Try to logout (must pass) - do("GET", "/Logout", noH, "", 200, "Logout OK") - -} - -/** -Banker TESTS (those tests are to check the bankers rights) -**/ -func BankerTests(t *testing.T) { - // Create the tester - ts, do, _ := createTester(t) - defer ts.Close() // Close the tester - tests := func() { - // Get the XSRF Token - response := do("GET", "/api/common/WhoAmI", noH, "", 200, "") - token := auth.TokenData{} - json.Unmarshal([]byte(response), &token) - xsrfHeader := tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} - + // Create one banker + do("POST", "/api/UserBankers", xsrfHeader, `{"UserID":3,"Name":"Banker"}`, 200, "") + // Create an other banker + do("POST", "/api/UserBankers", xsrfHeader, `{"UserID":6,"Name":"Banker 2"}`, 200, "") // Try to create a client - do("POST", "/api/UserClients", xsrfHeader, `{"ID":1,"UserID":1,"Name":"Dupond"}`, 200, "") + do("POST", "/api/UserClients", xsrfHeader, `{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1}`, 200, "") // Try to create an other one - do("POST", "/api/UserClients", xsrfHeader, `{"ID":2,"UserID":2,"Name":"Boulangerie"}`, 200, "") - // Try to get the first client - do("GET", "/api/UserClients/1", xsrfHeader, "", 200, `{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[]}`) - // Try to get all the clients - do("GET", "/api/UserClients", xsrfHeader, "", 200, `[{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[]},{"ID":2,"UserID":2,"Name":"Boulangerie","UserBankerID":1,"BankAccounts":[]}]`) - + do("POST", "/api/UserClients", xsrfHeader, `{"ID":2,"UserID":2,"Name":"Boulangerie","UserBankerID":2}`, 200, "") // Add bank account to client do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100}`, 200, "") - // Add an other bank account to client - do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0}`, 200, "") - // Get account where id=1 - do("GET", "/api/BankAccounts/1", xsrfHeader, "", 200, `{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":[]}`) - // Get all Bank account - do("GET", "/api/BankAccounts/", xsrfHeader, "", 200, `[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":[]},{"ID":2,"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0,"Operations":[]}]`) // Add a bank account to Bakery do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4745,"BankOverdraft":-500}`, 200, "") - // Add operation between client and Bakery - do("POST", "/api/Operations", xsrfHeader, `{"Debtor":1,"Amount":-100,"Creditor":3}`, 200, "") - // Get operation where id=1 - do("GET", "/api/Operations/1", xsrfHeader, "", 200, `{"ID":1,"Debtor":1,"Amount":-100`) - // Get Operations for creditor (opposite operation should have been registered) - do("GET", "/api/Operations/2", xsrfHeader, "", 200, `{"ID":2,"Debtor":3,"Amount":100`) - // Add invalid operation between client and Bakery must be refused with 417 (Expectation failed) - do("POST", "/api/Operations", xsrfHeader, `{"Debtor":1,"Amount":-1789,"Creditor":3}`, 417, "Not enough money") - - // Get client Dupond with his banks accounts and operations up to date (-100€ on checking-account) - do("GET", "/api/UserClients/1", xsrfHeader, "", 200, `{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":null},{"ID":2,"Number":"01-02","UserClientID":1,"Type":"saving-account","Amount":1287,"BankOverdraft":0,"Operations":null}]}`) - // Get client Bakery with his banks accounts and operations up to date (+100€ on checking-account) - do("GET", "/api/UserClients/2", xsrfHeader, "", 200, `{"ID":2,"UserID":2,"Name":"Boulangerie","UserBankerID":1,"BankAccounts":[{"ID":3,"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4845,"BankOverdraft":-500,"Operations":null}]}`) - - // Verify operation on client Dupond checking-account - do("GET", "/api/BankAccounts/1", xsrfHeader, "", 200, `{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":358,"BankOverdraft":-100,"Operations":[{"ID":1,"Debtor":1,"Amount":-100`) - // Verify operation on client Bakery checking-account - do("GET", "/api/BankAccounts/3", xsrfHeader, "", 200, `{"ID":3,"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4845,"BankOverdraft":-500,"Operations":[{"ID":2,"Debtor":3,"Amount":100`) - - // Try to delete the first operation - do("DELETE", "/api/Operations/1", xsrfHeader, ``, 200, "") - // Try to get the first user again - do("GET", "/api/Operations/1", xsrfHeader, "", 404, `id does not exist`) - // The operation id=2 (opposite operation) should also have been deleted - do("GET", "/api/Operations/2", xsrfHeader, "", 404, `id does not exist`) - - // Test that bank account have been updated after operations deletion - do("GET", "/api/BankAccounts/1", xsrfHeader, "", 200, `{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":[]}`) - do("GET", "/api/BankAccounts/3", xsrfHeader, "", 200, `{"ID":3,"Number":"02-01","UserClientID":2,"Type":"checking-account","Amount":4745,"BankOverdraft":-500,"Operations":[]}`) - - // Try to delete the saving account of Dupond - do("DELETE", "/api/BankAccounts/2", xsrfHeader, ``, 200, "") - // Try to get the first user again - do("GET", "/api/BankAccounts/2", xsrfHeader, "", 404, `id does not exist`) - - // Test that client have been updated after operations deletion and bank account deletion - // Get client Dupond with his banks accounts and operations up to date (-100€ on checking-account) - do("GET", "/api/UserClients/1", xsrfHeader, "", 200, `{"ID":1,"UserID":1,"Name":"Dupond","UserBankerID":1,"BankAccounts":[{"ID":1,"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100,"Operations":null}]}`) - - // Try to delete the bakery client - do("DELETE", "/api/UserClients/2", xsrfHeader, ``, 200, "") - // Try to get the first user again - do("GET", "/api/UserClients/2", xsrfHeader, "", 404, `id does not exist`) - - // Test that bank account have been deleted after client deletion - do("GET", "/api/BankAccounts/3", xsrfHeader, "", 404, `id does not exist`) - - do("GET", "/Logout", noH, "", 200, "Logout OK") - // Try to login with OAuth2 (must pass) should be logged as admin with admin role (banker) - do("POST", "/Login", noH, `{"login": "banker2","password": "password"}`, 200, "") - response = do("GET", "/api/common/WhoAmI", noH, "", 200, "") - token = auth.TokenData{} - json.Unmarshal([]byte(response), &token) - xsrfHeader = tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} - - // Try to create a client Dupont - do("POST", "/api/UserClients", xsrfHeader, `{"ID":5,"UserID":5,"Name":"Dupont"}`, 200, "") - // Try to get the banker's client - do("GET", "/api/UserClients/5", xsrfHeader, "", 200, `{"ID":5,"UserID":5,"Name":"Dupont","UserBankerID":2,"BankAccounts":[]}`) - // Try to get an other banker's client should fail with 403 - do("GET", "/api/UserClients/1", xsrfHeader, "", 403, `You can not access this ressource`) - // Add bank account to client - do("POST", "/api/BankAccounts", xsrfHeader, `{"Number":"04-01","UserClientID":5,"Type":"checking-account","Amount":200,"BankOverdraft":-50}`, 200, "") - // Get account where id=1 should fail as it's not an account of the banker's client - do("GET", "/api/BankAccounts/1", xsrfHeader, "", 403, `You can not access this ressource`) - // Get all Bank account - do("GET", "/api/BankAccounts/", xsrfHeader, "", 200, `[{"ID":4,"Number":"04-01","UserClientID":5,"Type":"checking-account","Amount":200,"BankOverdraft":-50,"Operations":[]}]`) - // Try to delete the checking-account account of Dupond should fail with 403 - do("DELETE", "/api/BankAccounts/1", xsrfHeader, ``, 403, `You can not access this ressource`) - // Try to delete Dupond should fail - do("DELETE", "/api/UserClients/1", xsrfHeader, ``, 403, `You can not access this ressource`) - - do("GET", "/Logout", noH, "", 200, "Logout OK") - do("POST", "/Login", noH, `{"login": "banker","password": "password"}`, 200, "") - response = do("GET", "/api/common/WhoAmI", noH, "", 200, "") - token = auth.TokenData{} - json.Unmarshal([]byte(response), &token) - xsrfHeader = tester.Header{Key: "XSRF-TOKEN", Value: token.XSRFToken} - - // logout and relog as local banker - // Try to get an other banker's client should fail with 403 - do("GET", "/api/UserClients/5", xsrfHeader, "", 403, `You can not access this ressource`) - // Try to get an other banker's client's account should fail with 403 - do("GET", "/api/BankAccounts/4", xsrfHeader, "", 403, `You can not access this ressource`) - // Try to delete the checking-account account of Dupont should fail with 403 - do("DELETE", "/api/BankAccounts/4", xsrfHeader, ``, 403, `You can not access this ressource`) - // Try to delete Dupont should fail - do("DELETE", "/api/UserClients/5", xsrfHeader, ``, 403, `You can not access this ressource`) } - // Do a in memory login with an known admin - do("POST", "/Login", noH, `{"login": "banker","password": "password"}`, 200, "") - tests() - // Try to logout (must pass) + do("POST", "/Login", noH, `{"login": "admin","password": "password"}`, 200, "") + init() do("GET", "/Logout", noH, "", 200, "Logout OK") } -func resetData() { - os.RemoveAll("./data") - os.Mkdir("data", os.ModePerm) - os.Create("./data/test.db") -} - func createTester(t *testing.T) (*httptest.Server, func(method string, url string, header tester.Header, payload string, expectedStatus int, expectedBody string) string, func(method string, url string, header tester.Header, payload string, expectedStatus int, expectedBody string) string) { // Create the server - resetData() mux := CreateRootMux(1443, "../../web") ts := httptest.NewServer(mux.Mux) url, _ := url.Parse(ts.URL) diff --git a/internal/rootmux/unlogged_test.go b/internal/rootmux/unlogged_test.go new file mode 100644 index 0000000000000000000000000000000000000000..2a445f0d5435502cdb77a4b9365b7fa04ee0a89e --- /dev/null +++ b/internal/rootmux/unlogged_test.go @@ -0,0 +1,59 @@ +package rootmux + +import ( + "net/http" + "testing" +) + +/** +UNLOGGED USER TESTS (this tests are to check that the security protections works) +**/ +func UnLoggedUserTests(t *testing.T) { + // Create the tester + ts, do, _ := createTester(t) + defer ts.Close() // Close the tester + // Try to access the main page (must pass) + do("GET", "/", noH, "", 200, "<!DOCTYPE html>") + // Try to get the user informations (must fail) + do("GET", "/api/common/WhoAmI", noH, "", 401, "error extracting token") + // Do a in memory login with an unknown user + do("POST", "/Login", noH, `{"login": "unknownuser","password": "password"}`, http.StatusForbidden, `user not found`) + // Do a in memory login with a known user but bad password + do("POST", "/Login", noH, `{"login": "admin","password": "badpassword"}`, http.StatusForbidden, `user not found`) + + // Without authent API calls must fails with 401 error extracting token + // Try to get the first client should fail + do("GET", "/api/UserClients/1", noH, "", 401, `error extracting token`) + // Try to get all clients should fail + do("GET", "/api/UserClients", noH, "", 401, `error extracting token`) + // Try to get the first operation should fail + do("GET", "/api/UserBankers/1", noH, "", 401, `error extracting token`) + // Try to get all clients should fail + do("GET", "/api/UserBankers", noH, "", 401, `error extracting token`) + // Try to get the first operation should fail + do("GET", "/api/Operations/1", noH, "", 401, `error extracting token`) + // Try to get all operations should fail + do("GET", "/api/Operations", noH, "", 401, `error extracting token`) + // Try to get the first BankAccount should fail + do("GET", "/api/BankAccounts/1", noH, "", 401, `error extracting token`) + // Try to get all BankAccounts should fail + do("GET", "/api/BankAccounts", noH, "", 401, `error extracting token`) + + // Unlogged user should not be able to create a Client + do("POST", "/api/UserClients", noH, `{"Name":"Dupond"}`, 401, `error extracting token`) + // Unlogged user should not be able to create a Banker + do("POST", "/api/UserBankers", noH, `{"Name":"Dupond"}`, 401, `error extracting token`) + // Unlogged user should not be able to create a Bank Account + do("POST", "/api/BankAccounts", noH, `{"Number":"01-01","UserClientID":1,"Type":"checking-account","Amount":458,"BankOverdraft":-100}`, 401, `error extracting token`) + // Unlogged user should not be able to create an Operation + do("POST", "/api/Operations", noH, `{"Debtor":1,"Amount":-100,"Creditor":3}`, 401, `error extracting token`) + + // Unlogged user should not be able to delete an Operation + do("DELETE", "/api/Operations/1", noH, ``, 401, "error extracting token") + // Unlogged user should not be able to delete a BankAccount + do("DELETE", "/api/BankAccounts/2", noH, ``, 401, "error extracting token") + // Unlogged user should not be able to delete a Client + do("DELETE", "/api/UserClients/2", noH, ``, 401, "error extracting token") + // Unlogged user should not be able to delete a Banker + do("DELETE", "/api/UserBankers/2", noH, ``, 401, "error extracting token") +} diff --git a/pkg/auth/oauth2.go b/pkg/auth/oauth2.go index acc9b9f370e0c73ff82ed689a0b3d968096fe3d9..7562c705e9cf398d944bc89f9beb108868c843c2 100644 --- a/pkg/auth/oauth2.go +++ b/pkg/auth/oauth2.go @@ -168,7 +168,7 @@ func addUserInMemory(userOauth2 UserOAuth2) (User, error) { var user User for _, userRole := range userOauth2.Roles { if userRole != "" && (userRole == os.Getenv("ADMIN_GROUP")) { - user.Role = "ADMINS" + user.Role = "ADMIN" } else if userRole != "" && (userRole == os.Getenv("CLIENT_GROUP")) { user.Role = "CLIENT" } else {